<commit_before>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: MPL-2.0
//

use Result;

use client::Api;
use firmware::installation_set;
use states::{Idle, Install, State, StateChangeImpl, StateMachine, TransitionCallback};
use std::fs;
use update_package::{ObjectStatus, UpdatePackage};
use walkdir::WalkDir;

#[derive(Debug, PartialEq)]
pub struct Download {
    pub update_package: UpdatePackage,
}

create_state_step!(Download => Idle);
create_state_step!(Download => Install(update_package));

impl TransitionCallback for State<Download> {
    fn callback_state_name(&self) -> &'static str {
        "download"
    }
}

impl StateChangeImpl for State<Download> {
    fn handle(self) -> Result<StateMachine> {
        let installation_set = installation_set::inactive()?;

        // Prune left over from previous installations
        for entry in WalkDir::new(&self.settings.update.download_dir)
            .follow_links(true)
            .min_depth(1)
            .into_iter()
            .filter_entry(|e| e.file_type().is_file())
            .filter_map(|e| e.ok())
            .filter(|e| {
                !self
                    .state
                    .update_package
                    .objects(installation_set)
                    .iter()
                    .map(|o| o.sha256sum())
                    .collect::<Vec<_>>()
                    .contains(&e.file_name().to_str().unwrap_or(""))
            }) {
            fs::remove_file(entry.path())?;
        }

        // Prune corrupted files
        for object in self.state.update_package.filter_objects(
            &self.settings,
            installation_set,
            &ObjectStatus::Corrupted,
        ) {
            fs::remove_file(&self.settings.update.download_dir.join(object.sha256sum()))?;
        }

        // Download the missing or incomplete objects
        for object in self
            .state
            .update_package
            .filter_objects(&self.settings, installation_set, &ObjectStatus::Missing)
            .into_iter()
            .chain(self.state.update_package.filter_objects(
                &self.settings,
                installation_set,
                &ObjectStatus::Incomplete,
            )) {
            Api::new(&self.settings, &self.runtime_settings, &self.firmware)
                .download_object(&self.state.update_package.package_uid(), object.sha256sum())?;
        }

        if self
            .state
            .update_package
            .objects(installation_set)
            .iter()
            .all(|o| o.status(&self.settings.update.download_dir).ok() == Some(ObjectStatus::Ready))
        {
            Ok(StateMachine::Install(self.into()))
        } else {
            bail!("Not all objects are ready for use")
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    fn fake_download_state() -> State<Download> {
        use firmware::{
            tests::{create_fake_installation_set, create_fake_metadata, FakeDevice},
            Metadata,
        };
        use runtime_settings::RuntimeSettings;
        use std::{env, fs::create_dir_all};
        use update_package::tests::{create_fake_settings, get_update_package};

        let settings = create_fake_settings();
        let tmpdir = settings.update.download_dir.clone();
        let _ = create_dir_all(&tmpdir);
        create_fake_installation_set(&tmpdir, 0);
        env::set_var("PATH", format!("{}", &tmpdir.to_string_lossy()));

        State {
            settings,
            runtime_settings: RuntimeSettings::default(),
            firmware: Metadata::new(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap(),
            state: Download {
                update_package: get_update_package(),
            },
        }
    }

    #[test]
    fn skip_download_if_ready() {
        use update_package::tests::create_fake_object;

        let download_state = fake_download_state();
        let tmpdir = download_state.settings.update.download_dir.clone();

        create_fake_object(&download_state.settings);

        let machine = StateMachine::Download(download_state).move_to_next_state();
        assert_state!(machine, Install);

        assert_eq!(
            WalkDir::new(&tmpdir)
                .follow_links(true)
                .min_depth(1)
                .into_iter()
                .filter_entry(|e| e.file_type().is_file())
                .count(),
            1,
            "Number of objects is wrong"
        );
    }

    #[test]
    fn download_objects() {
        use crypto_hash::{hex_digest, Algorithm};
        use mockito::mock;
        use std::fs::File;
        use std::io::Read;

        let sha256sum = "c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646";
        let download_state = fake_download_state();
        let tmpdir = download_state.settings.update.download_dir.clone();

        // leftover file to ensure it is removed
        let _ = File::create(&tmpdir.join("leftover-file"));

        let mock = mock(
            "GET",
            format!(
                "/products/{}/packages/{}/objects/{}",
                "229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
                &download_state.state.update_package.package_uid(),
                &sha256sum
            ).as_str(),
        ).match_header("Content-Type", "application/json")
        .match_header("Api-Content-Type", "application/vnd.updatehub-v1+json")
        .with_status(200)
        .with_body("1234567890")
        .create();

        let machine = StateMachine::Download(download_state).move_to_next_state();
        assert_state!(machine, Install);

        mock.assert();

        assert_eq!(
            WalkDir::new(&tmpdir)
                .follow_links(true)
                .min_depth(1)
                .into_iter()
                .filter_entry(|e| e.file_type().is_file())
                .count(),
            1,
            "Failed to remove the corrupted object"
        );

        let mut object_content = String::new();
        let _ = File::open(&tmpdir.join(&sha256sum))
            .expect("Fail to open the temporary directory.")
            .read_to_string(&mut object_content);

        assert_eq!(
            &hex_digest(Algorithm::SHA256, object_content.as_bytes()),
            &sha256sum,
            "Checksum mismatch"
        );
    }

    #[test]
    fn download_has_transition_callback_trait() {
        let download_state = fake_download_state();
        assert_eq!(download_state.callback_state_name(), "download");
    }
}
<commit_msg>states: download: Remove useless `.collect()` call<commit_after>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: MPL-2.0
//

use Result;

use client::Api;
use firmware::installation_set;
use states::{Idle, Install, State, StateChangeImpl, StateMachine, TransitionCallback};
use std::fs;
use update_package::{ObjectStatus, UpdatePackage};
use walkdir::WalkDir;

#[derive(Debug, PartialEq)]
pub struct Download {
    pub update_package: UpdatePackage,
}

create_state_step!(Download => Idle);
create_state_step!(Download => Install(update_package));

impl TransitionCallback for State<Download> {
    fn callback_state_name(&self) -> &'static str {
        "download"
    }
}

impl StateChangeImpl for State<Download> {
    fn handle(self) -> Result<StateMachine> {
        let installation_set = installation_set::inactive()?;

        // Prune left over from previous installations
        for entry in WalkDir::new(&self.settings.update.download_dir)
            .follow_links(true)
            .min_depth(1)
            .into_iter()
            .filter_entry(|e| e.file_type().is_file())
            .filter_map(|e| e.ok())
            .filter(|e| {
                !self
                    .state
                    .update_package
                    .objects(installation_set)
                    .iter()
                    .map(|o| o.sha256sum())
                    .any(|x| x == e.file_name())
            }) {
            fs::remove_file(entry.path())?;
        }

        // Prune corrupted files
        for object in self.state.update_package.filter_objects(
            &self.settings,
            installation_set,
            &ObjectStatus::Corrupted,
        ) {
            fs::remove_file(&self.settings.update.download_dir.join(object.sha256sum()))?;
        }

        // Download the missing or incomplete objects
        for object in self
            .state
            .update_package
            .filter_objects(&self.settings, installation_set, &ObjectStatus::Missing)
            .into_iter()
            .chain(self.state.update_package.filter_objects(
                &self.settings,
                installation_set,
                &ObjectStatus::Incomplete,
            )) {
            Api::new(&self.settings, &self.runtime_settings, &self.firmware)
                .download_object(&self.state.update_package.package_uid(), object.sha256sum())?;
        }

        if self
            .state
            .update_package
            .objects(installation_set)
            .iter()
            .all(|o| o.status(&self.settings.update.download_dir).ok() == Some(ObjectStatus::Ready))
        {
            Ok(StateMachine::Install(self.into()))
        } else {
            bail!("Not all objects are ready for use")
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    fn fake_download_state() -> State<Download> {
        use firmware::{
            tests::{create_fake_installation_set, create_fake_metadata, FakeDevice},
            Metadata,
        };
        use runtime_settings::RuntimeSettings;
        use std::{env, fs::create_dir_all};
        use update_package::tests::{create_fake_settings, get_update_package};

        let settings = create_fake_settings();
        let tmpdir = settings.update.download_dir.clone();
        let _ = create_dir_all(&tmpdir);
        create_fake_installation_set(&tmpdir, 0);
        env::set_var("PATH", format!("{}", &tmpdir.to_string_lossy()));

        State {
            settings,
            runtime_settings: RuntimeSettings::default(),
            firmware: Metadata::new(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap(),
            state: Download {
                update_package: get_update_package(),
            },
        }
    }

    #[test]
    fn skip_download_if_ready() {
        use update_package::tests::create_fake_object;

        let download_state = fake_download_state();
        let tmpdir = download_state.settings.update.download_dir.clone();

        create_fake_object(&download_state.settings);

        let machine = StateMachine::Download(download_state).move_to_next_state();
        assert_state!(machine, Install);

        assert_eq!(
            WalkDir::new(&tmpdir)
                .follow_links(true)
                .min_depth(1)
                .into_iter()
                .filter_entry(|e| e.file_type().is_file())
                .count(),
            1,
            "Number of objects is wrong"
        );
    }

    #[test]
    fn download_objects() {
        use crypto_hash::{hex_digest, Algorithm};
        use mockito::mock;
        use std::fs::File;
        use std::io::Read;

        let sha256sum = "c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646";
        let download_state = fake_download_state();
        let tmpdir = download_state.settings.update.download_dir.clone();

        // leftover file to ensure it is removed
        let _ = File::create(&tmpdir.join("leftover-file"));

        let mock = mock(
            "GET",
            format!(
                "/products/{}/packages/{}/objects/{}",
                "229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
                &download_state.state.update_package.package_uid(),
                &sha256sum
            ).as_str(),
        ).match_header("Content-Type", "application/json")
        .match_header("Api-Content-Type", "application/vnd.updatehub-v1+json")
        .with_status(200)
        .with_body("1234567890")
        .create();

        let machine = StateMachine::Download(download_state).move_to_next_state();
        assert_state!(machine, Install);

        mock.assert();

        assert_eq!(
            WalkDir::new(&tmpdir)
                .follow_links(true)
                .min_depth(1)
                .into_iter()
                .filter_entry(|e| e.file_type().is_file())
                .count(),
            1,
            "Failed to remove the corrupted object"
        );

        let mut object_content = String::new();
        let _ = File::open(&tmpdir.join(&sha256sum))
            .expect("Fail to open the temporary directory.")
            .read_to_string(&mut object_content);

        assert_eq!(
            &hex_digest(Algorithm::SHA256, object_content.as_bytes()),
            &sha256sum,
            "Checksum mismatch"
        );
    }

    #[test]
    fn download_has_transition_callback_trait() {
        let download_state = fake_download_state();
        assert_eq!(download_state.callback_state_name(), "download");
    }
}
<|endoftext|>


<commit_before>extern crate websocket;

use std::thread;
use websocket::sync::Server;
use websocket::OwnedMessage;

fn main() {
  let server = Server::bind("127.0.0.1:8500").unwrap();

  for request in server.filter_map(Result::ok) {
    // Spawn a new thread for each connection.
    thread::spawn(move || {
      if !request.protocols().contains(&"rust-websocket".to_string()) {
        request.reject().unwrap();
        return;
      }

      let mut client = request.use_protocol("rust-websocket").accept().unwrap();

      let ip = client.peer_addr().unwrap();

      println!("Connection from {}", ip);

      // TODO send up controls.

      /*      let (sender, mut receiver) = client.split();
            // register the sender with broadcaster.
            let sendmeh = Arc::new(Mutex::new(sender));
            broadcaster.register(sendmeh.clone());
      */

      let message = OwnedMessage::Text("Hello".to_string());
      client.send_message(&message).unwrap();

      //(websocket::receiver::Reader<std::net::TcpStream>, websocket::sender::Writer<std::net::TcpStream> )
      let (mut receiver, mut sender) = client.split().unwrap();

      for message in receiver.incoming_messages() {
        // TODO message handler here.
        let message = message.unwrap();

        match message {
          OwnedMessage::Close(_) => {
            let message = OwnedMessage::Close(None);
            sender.send_message(&message).unwrap();
            println!("Client {} disconnected", ip);
            return;
          }
          OwnedMessage::Ping(ping) => {
            let message = OwnedMessage::Pong(ping);
            sender.send_message(&message).unwrap();
          }
          _ => sender.send_message(&message).unwrap(),
        }
      }
    });
  }
}

/*
 // send up the json of the current controls.
 {
   let sci = ci.lock().unwrap();

   let updarray = controls::cm_to_update_array(&sci.cm);

   // build json message containing both guijson and the updarray.
   let mut updvals = Vec::new();

   for upd in updarray {
     let um = json::encode_update_message(&upd);
     updvals.push(um);
   }

   let mut guival: Value = try!(serde_json::from_str(&sci.guijson[..]));

   match guival.as_object_mut() {
     Some(obj) => {
       obj.insert("state".to_string(), Value::Array(updvals));
       ()
     }
     None => (),
   }

   let guistring = try!(serde_json::ser::to_string(&guival));
   let message = Message::text(guistring);
   try!(client.send_message(&message));
}*/

/*
   Message handler

{
    let message: Message = try!(msg);
    // println!("message: {:?}", message);

    match message.opcode {
      Type::Close => {
        let message = Message::close();
        // let mut sender = try!(sendmeh.lock());
        let mut sender = sendmeh.lock().unwrap();
        try!(sender.send_message(&mut *sender, &message));
        println!("Client {} disconnected", ip);
        return Ok(());
      }
      Type::Ping => {
        println!("Message::Ping(data)");
        let message = Message::pong(message.payload);
        let mut sender = sendmeh.lock().unwrap();
        try!(sender.send_message(*sender, &message));
      }
      Type::Text => {
        let u8 = message.payload.to_owned();
        let str = try!(std::str::from_utf8(&*u8));
        let jsonval: Value = try!(serde_json::from_str(str));
        let s_um = json::decode_update_message(&jsonval);
        match s_um {
          Some(updmsg) => {
            {
              let mut sci = ci.lock().unwrap();
              {
                let mbcntrl = sci.cm.get_mut(controls::get_um_id(&updmsg));
                match mbcntrl {
                  Some(cntrl) => {
                    (*cntrl).update(&updmsg);
                    broadcaster.broadcast_others(&ip, Message::text(str));
                    ()
                  }
                  None => println!("none"),
                }
              }
            }
            let mut scup = cup.lock().unwrap();
            let sci = match ci.lock() {
              Ok(sci) => sci,
              Err(poisoned) => poisoned.into_inner(),
            };

            scup.on_update_received(&updmsg, &*sci);
          }
          _ => println!(
            "decode_update_message failed on websockets msg: {:?}",
            message
          ),
        }
      }
      _ => {
        println!("unknown websockets msg: {:?}", message);
      }
    }
  }*/
<commit_msg>more of the old stuff, temporarily<commit_after>extern crate websocket;

use std::thread;
use websocket::sync::Server;
use websocket::OwnedMessage;

pub fn startserver<'a>(
  guistring: &str,
  cup: Box<ControlUpdateProcessor>,
  ip: &str,
  websockets_port: &str,
) -> Result<ControlServer, Box<std::error::Error>> {
  let guival: Value = try!(serde_json::from_str(guistring));

  let blah = try!(json::deserialize_root(&guival));

  println!(
    "title: {} rootcontroltype: {} ",
    blah.title,
    blah.root_control.control_type()
  );
  println!("controls: {:?}", blah.root_control);

  // from control tree, make a map of ids->controls.
  let mapp = controls::make_control_map(&*blah.root_control);
  let cnm = controls::control_map_to_name_map(&mapp);

  let ci = ControlInfo {
    cm: mapp,
    cnm: cnm,
    guijson: String::new() + guistring,
  };

  let cmshare = Arc::new(Mutex::new(ci));
  let wscmshare = cmshare.clone();
  // for sending, bind to this.  if we bind to localhost, we can't
  // send messages to other machines.
  let bc = broadcaster::Broadcaster::new();
  let wsbc = bc.clone();

  let cs_ret = ControlServer {
    ci: cmshare,
    bc: bc,
  };

  // Spawn a thread for the websockets handler.
  thread::spawn(move || {
    match websockets_main(websockets_ip, wscmshare, wsbc, Arc::new(Mutex::new(cup))) {
      Ok(_) => (),
      Err(e) => println!("error in websockets_main: {:?}", e),
    }
  });

  Ok(cs_ret)
}

fn websockets_main(
  ipaddr: String,
  ci: Arc<Mutex<ControlInfo>>,
  broadcaster: broadcaster::Broadcaster,
  cup: Arc<Mutex<Box<ControlUpdateProcessor>>>,
) -> Result<(), Box<std::error::Error>> {
  let server = try!(Server::bind(&ipaddr[..]));

  for connection in server {
    // Spawn a new thread for each connection.
    println!("new websockets connection!");
    let conn = try!(connection);
    let sci = ci.clone();
    let broadcaster = broadcaster.clone();
    let cup = cup.clone();
    thread::spawn(
      move || match websockets_client(conn, sci, broadcaster, cup) {
        Ok(_) => (),
        Err(e) => {
          println!("error in websockets thread: {:?}", e);
          ()
        }
      },
    );
  }

  Ok(())
}

fn websockets_main() {
  let server = Server::bind("127.0.0.1:8500").unwrap();

  for request in server.filter_map(Result::ok) {
    // Spawn a new thread for each connection.
    thread::spawn(move || {
      if !request.protocols().contains(&"rust-websocket".to_string()) {
        request.reject().unwrap();
        return;
      }

      let mut client = request.use_protocol("rust-websocket").accept().unwrap();

      let ip = client.peer_addr().unwrap();

      println!("Connection from {}", ip);

      // TODO send up controls.

      /*      let (sender, mut receiver) = client.split();
            // register the sender with broadcaster.
            let sendmeh = Arc::new(Mutex::new(sender));
            broadcaster.register(sendmeh.clone());
      */

      let message = OwnedMessage::Text("Hello".to_string());
      client.send_message(&message).unwrap();

      //(websocket::receiver::Reader<std::net::TcpStream>, websocket::sender::Writer<std::net::TcpStream> )
      let (mut receiver, mut sender) = client.split().unwrap();

      for message in receiver.incoming_messages() {
        // TODO message handler here.
        let message = message.unwrap();

        match message {
          OwnedMessage::Close(_) => {
            let message = OwnedMessage::Close(None);
            sender.send_message(&message).unwrap();
            println!("Client {} disconnected", ip);
            return;
          }
          OwnedMessage::Ping(ping) => {
            let message = OwnedMessage::Pong(ping);
            sender.send_message(&message).unwrap();
          }
          _ => sender.send_message(&message).unwrap(),
        }
      }
    });
  }
}

/*
 // send up the json of the current controls.
 {
   let sci = ci.lock().unwrap();

   let updarray = controls::cm_to_update_array(&sci.cm);

   // build json message containing both guijson and the updarray.
   let mut updvals = Vec::new();

   for upd in updarray {
     let um = json::encode_update_message(&upd);
     updvals.push(um);
   }

   let mut guival: Value = try!(serde_json::from_str(&sci.guijson[..]));

   match guival.as_object_mut() {
     Some(obj) => {
       obj.insert("state".to_string(), Value::Array(updvals));
       ()
     }
     None => (),
   }

   let guistring = try!(serde_json::ser::to_string(&guival));
   let message = Message::text(guistring);
   try!(client.send_message(&message));
}*/

/*
   Message handler

{
    let message: Message = try!(msg);
    // println!("message: {:?}", message);

    match message.opcode {
      Type::Close => {
        let message = Message::close();
        // let mut sender = try!(sendmeh.lock());
        let mut sender = sendmeh.lock().unwrap();
        try!(sender.send_message(&mut *sender, &message));
        println!("Client {} disconnected", ip);
        return Ok(());
      }
      Type::Ping => {
        println!("Message::Ping(data)");
        let message = Message::pong(message.payload);
        let mut sender = sendmeh.lock().unwrap();
        try!(sender.send_message(*sender, &message));
      }
      Type::Text => {
        let u8 = message.payload.to_owned();
        let str = try!(std::str::from_utf8(&*u8));
        let jsonval: Value = try!(serde_json::from_str(str));
        let s_um = json::decode_update_message(&jsonval);
        match s_um {
          Some(updmsg) => {
            {
              let mut sci = ci.lock().unwrap();
              {
                let mbcntrl = sci.cm.get_mut(controls::get_um_id(&updmsg));
                match mbcntrl {
                  Some(cntrl) => {
                    (*cntrl).update(&updmsg);
                    broadcaster.broadcast_others(&ip, Message::text(str));
                    ()
                  }
                  None => println!("none"),
                }
              }
            }
            let mut scup = cup.lock().unwrap();
            let sci = match ci.lock() {
              Ok(sci) => sci,
              Err(poisoned) => poisoned.into_inner(),
            };

            scup.on_update_received(&updmsg, &*sci);
          }
          _ => println!(
            "decode_update_message failed on websockets msg: {:?}",
            message
          ),
        }
      }
      _ => {
        println!("unknown websockets msg: {:?}", message);
      }
    }
  }*/
<|endoftext|>


<commit_before>use app_units::Au;
use display_item::{DisplayItem, SpecificDisplayItem, ImageDisplayItem};
use display_item::{RectangleDisplayItem, TextDisplayItem, GradientDisplayItem};
use display_item::{BorderDisplayItem, BoxShadowDisplayItem};
use euclid::{Point2D, Rect, Size2D};
use std::mem;
use types::{ClipRegion, ColorF, FontKey, ImageKey, PipelineId, StackingLevel};
use types::{BorderRadius, BorderSide, BoxShadowClipMode, GlyphInstance};
use types::{DisplayListMode, GradientStop, StackingContextId};

pub struct DrawListInfo {
    pub items: Vec<DisplayItem>,
}

pub struct StackingContextInfo {
    pub id: StackingContextId,
}

#[derive(Debug, Clone)]
pub struct IframeInfo {
    pub id: PipelineId,
    pub offset: Point2D<f32>,
    pub clip: Rect<f32>,
}

pub enum SpecificDisplayListItem {
    DrawList(DrawListInfo),
    StackingContext(StackingContextInfo),
    Iframe(Box<IframeInfo>),
}

pub struct DisplayListItem {
    pub stacking_level: StackingLevel,
    pub specific: SpecificDisplayListItem,
}

pub struct DisplayListBuilder {
    pub mode: DisplayListMode,
    pub has_stacking_contexts: bool,

    pub work_background_and_borders: Vec<DisplayItem>,
    pub work_block_backgrounds_and_borders: Vec<DisplayItem>,
    pub work_floats: Vec<DisplayItem>,
    pub work_content: Vec<DisplayItem>,
    pub work_positioned_content: Vec<DisplayItem>,
    pub work_outlines: Vec<DisplayItem>,

    pub items: Vec<DisplayListItem>,
}

impl DisplayListBuilder {
    pub fn new() -> DisplayListBuilder {
        DisplayListBuilder {
            mode: DisplayListMode::Default,
            has_stacking_contexts: false,

            work_background_and_borders: Vec::new(),
            work_block_backgrounds_and_borders: Vec::new(),
            work_floats: Vec::new(),
            work_content: Vec::new(),
            work_positioned_content: Vec::new(),
            work_outlines: Vec::new(),

            items: Vec::new(),
        }
    }

    pub fn push_rect(&mut self,
                     level: StackingLevel,
                     rect: Rect<f32>,
                     clip: ClipRegion,
                     color: ColorF) {
        let item = RectangleDisplayItem {
            color: color,
        };

        let display_item = DisplayItem {
            item: SpecificDisplayItem::Rectangle(item),
            rect: rect,
            clip: clip,
        };

        self.push_item(level, display_item);
    }

    pub fn push_image(&mut self,
                      level: StackingLevel,
                      rect: Rect<f32>,
                      clip: ClipRegion,
                      stretch_size: Size2D<f32>,
                      key: ImageKey) {
        let item = ImageDisplayItem {
            image_key: key,
            stretch_size: stretch_size,
        };

        let display_item = DisplayItem {
            item: SpecificDisplayItem::Image(item),
            rect: rect,
            clip: clip,
        };

        self.push_item(level, display_item);
    }

    pub fn push_text(&mut self,
                     level: StackingLevel,
                     rect: Rect<f32>,
                     clip: ClipRegion,
                     glyphs: Vec<GlyphInstance>,
                     font_key: FontKey,
                     color: ColorF,
                     size: Au,
                     blur_radius: Au) {
        let item = TextDisplayItem {
            color: color,
            glyphs: glyphs,
            font_key: font_key,
            size: size,
            blur_radius: blur_radius,
        };

        let display_item = DisplayItem {
            item: SpecificDisplayItem::Text(item),
            rect: rect,
            clip: clip,
        };

        self.push_item(level, display_item);
    }

    pub fn push_border(&mut self,
                       level: StackingLevel,
                       rect: Rect<f32>,
                       clip: ClipRegion,
                       left: BorderSide,
                       top: BorderSide,
                       right: BorderSide,
                       bottom: BorderSide,
                       radius: BorderRadius) {
        let item = BorderDisplayItem {
            left: left,
            top: top,
            right: right,
            bottom: bottom,
            radius: radius,
        };

        let display_item = DisplayItem {
            item: SpecificDisplayItem::Border(item),
            rect: rect,
            clip: clip,
        };

        self.push_item(level, display_item);
    }

    pub fn push_box_shadow(&mut self,
                           level: StackingLevel,
                           rect: Rect<f32>,
                           clip: ClipRegion,
                           box_bounds: Rect<f32>,
                           offset: Point2D<f32>,
                           color: ColorF,
                           blur_radius: f32,
                           spread_radius: f32,
                           border_radius: f32,
                           clip_mode: BoxShadowClipMode) {
        let item = BoxShadowDisplayItem {
            box_bounds: box_bounds,
            offset: offset,
            color: color,
            blur_radius: blur_radius,
            spread_radius: spread_radius,
            border_radius: border_radius,
            clip_mode: clip_mode,
        };

        let display_item = DisplayItem {
            item: SpecificDisplayItem::BoxShadow(item),
            rect: rect,
            clip: clip,
        };

        self.push_item(level, display_item);
    }

    pub fn push_stacking_context(&mut self,
                                 level: StackingLevel,
                                 stacking_context_id: StackingContextId) {
        self.has_stacking_contexts = true;
        self.flush_list(level);
        let info = StackingContextInfo {
            id: stacking_context_id,
        };
        let item = DisplayListItem {
            stacking_level: level,
            specific: SpecificDisplayListItem::StackingContext(info),
        };
        self.items.push(item);
    }

    pub fn push_gradient(&mut self,
                         level: StackingLevel,
                         rect: Rect<f32>,
                         clip: ClipRegion,
                         start_point: Point2D<f32>,
                         end_point: Point2D<f32>,
                         stops: Vec<GradientStop>) {
        let item = GradientDisplayItem {
            start_point: start_point,
            end_point: end_point,
            stops: stops,
        };

        let display_item = DisplayItem {
            item: SpecificDisplayItem::Gradient(item),
            rect: rect,
            clip: clip,
        };

        self.push_item(level, display_item);
    }

    pub fn push_iframe(&mut self,
                       level: StackingLevel,
                       rect: Rect<f32>,
                       _clip: ClipRegion,
                       iframe: PipelineId) {
        self.flush_list(level);
        let info = Box::new(IframeInfo {
            id: iframe,
            offset: rect.origin,
            clip: rect,
        });
        let item = DisplayListItem {
            stacking_level: level,
            specific: SpecificDisplayListItem::Iframe(info),
        };
        self.items.push(item);
    }

    fn push_item(&mut self, level: StackingLevel, item: DisplayItem) {
        match level {
            StackingLevel::BackgroundAndBorders => {
                self.work_background_and_borders.push(item);
            }
            StackingLevel::BlockBackgroundAndBorders => {
                self.work_block_backgrounds_and_borders.push(item);
            }
            StackingLevel::Floats => {
                self.work_floats.push(item);
            }
            StackingLevel::Content => {
                self.work_content.push(item);
            }
            StackingLevel::PositionedContent => {
                self.work_positioned_content.push(item);
            }
            StackingLevel::Outlines => {
                self.work_outlines.push(item);
            }
        }
    }

    fn flush_list(&mut self, level: StackingLevel) {
        let list = match level {
            StackingLevel::BackgroundAndBorders => {
                &mut self.work_background_and_borders
            }
            StackingLevel::BlockBackgroundAndBorders => {
                &mut self.work_block_backgrounds_and_borders
            }
            StackingLevel::Floats => {
                &mut self.work_floats
            }
            StackingLevel::Content => {
                &mut self.work_content
            }
            StackingLevel::PositionedContent => {
                &mut self.work_positioned_content
            }
            StackingLevel::Outlines => {
                &mut self.work_outlines
            }
        };

        let items = mem::replace(list, Vec::new());
        if items.len() > 0 {
            let draw_list = DrawListInfo {
                items: items,
            };
            self.items.push(DisplayListItem {
                stacking_level: level,
                specific: SpecificDisplayListItem::DrawList(draw_list),
            });
        }
    }

    fn flush(&mut self) {
        self.flush_list(StackingLevel::BackgroundAndBorders);
        self.flush_list(StackingLevel::BlockBackgroundAndBorders);
        self.flush_list(StackingLevel::Floats);
        self.flush_list(StackingLevel::Content);
        self.flush_list(StackingLevel::PositionedContent);
        self.flush_list(StackingLevel::Outlines);
    }

    pub fn finalize(&mut self) {
        self.flush();
    }
}
<commit_msg>Fix font_advance reftest<commit_after>use app_units::Au;
use display_item::{DisplayItem, SpecificDisplayItem, ImageDisplayItem};
use display_item::{RectangleDisplayItem, TextDisplayItem, GradientDisplayItem};
use display_item::{BorderDisplayItem, BoxShadowDisplayItem};
use euclid::{Point2D, Rect, Size2D};
use std::mem;
use types::{ClipRegion, ColorF, FontKey, ImageKey, PipelineId, StackingLevel};
use types::{BorderRadius, BorderSide, BoxShadowClipMode, GlyphInstance};
use types::{DisplayListMode, GradientStop, StackingContextId};

pub struct DrawListInfo {
    pub items: Vec<DisplayItem>,
}

pub struct StackingContextInfo {
    pub id: StackingContextId,
}

#[derive(Debug, Clone)]
pub struct IframeInfo {
    pub id: PipelineId,
    pub offset: Point2D<f32>,
    pub clip: Rect<f32>,
}

pub enum SpecificDisplayListItem {
    DrawList(DrawListInfo),
    StackingContext(StackingContextInfo),
    Iframe(Box<IframeInfo>),
}

pub struct DisplayListItem {
    pub stacking_level: StackingLevel,
    pub specific: SpecificDisplayListItem,
}

pub struct DisplayListBuilder {
    pub mode: DisplayListMode,
    pub has_stacking_contexts: bool,

    pub work_background_and_borders: Vec<DisplayItem>,
    pub work_block_backgrounds_and_borders: Vec<DisplayItem>,
    pub work_floats: Vec<DisplayItem>,
    pub work_content: Vec<DisplayItem>,
    pub work_positioned_content: Vec<DisplayItem>,
    pub work_outlines: Vec<DisplayItem>,

    pub items: Vec<DisplayListItem>,
}

impl DisplayListBuilder {
    pub fn new() -> DisplayListBuilder {
        DisplayListBuilder {
            mode: DisplayListMode::Default,
            has_stacking_contexts: false,

            work_background_and_borders: Vec::new(),
            work_block_backgrounds_and_borders: Vec::new(),
            work_floats: Vec::new(),
            work_content: Vec::new(),
            work_positioned_content: Vec::new(),
            work_outlines: Vec::new(),

            items: Vec::new(),
        }
    }

    pub fn push_rect(&mut self,
                     level: StackingLevel,
                     rect: Rect<f32>,
                     clip: ClipRegion,
                     color: ColorF) {
        let item = RectangleDisplayItem {
            color: color,
        };

        let display_item = DisplayItem {
            item: SpecificDisplayItem::Rectangle(item),
            rect: rect,
            clip: clip,
        };

        self.push_item(level, display_item);
    }

    pub fn push_image(&mut self,
                      level: StackingLevel,
                      rect: Rect<f32>,
                      clip: ClipRegion,
                      stretch_size: Size2D<f32>,
                      key: ImageKey) {
        let item = ImageDisplayItem {
            image_key: key,
            stretch_size: stretch_size,
        };

        let display_item = DisplayItem {
            item: SpecificDisplayItem::Image(item),
            rect: rect,
            clip: clip,
        };

        self.push_item(level, display_item);
    }

    pub fn push_text(&mut self,
                     level: StackingLevel,
                     rect: Rect<f32>,
                     clip: ClipRegion,
                     glyphs: Vec<GlyphInstance>,
                     font_key: FontKey,
                     color: ColorF,
                     size: Au,
                     blur_radius: Au) {
        // Sanity check - anything with glyphs bigger than this
        // is probably going to consume too much memory to render
        // efficiently anyway. This is specifically to work around
        // the font_advance.html reftest, which creates a very large
        // font as a crash test - the rendering is also ignored
        // by the azure renderer.
        if size < Au::from_px(4096) {
            let item = TextDisplayItem {
                color: color,
                glyphs: glyphs,
                font_key: font_key,
                size: size,
                blur_radius: blur_radius,
            };

            let display_item = DisplayItem {
                item: SpecificDisplayItem::Text(item),
                rect: rect,
                clip: clip,
            };

            self.push_item(level, display_item);
        }
    }

    pub fn push_border(&mut self,
                       level: StackingLevel,
                       rect: Rect<f32>,
                       clip: ClipRegion,
                       left: BorderSide,
                       top: BorderSide,
                       right: BorderSide,
                       bottom: BorderSide,
                       radius: BorderRadius) {
        let item = BorderDisplayItem {
            left: left,
            top: top,
            right: right,
            bottom: bottom,
            radius: radius,
        };

        let display_item = DisplayItem {
            item: SpecificDisplayItem::Border(item),
            rect: rect,
            clip: clip,
        };

        self.push_item(level, display_item);
    }

    pub fn push_box_shadow(&mut self,
                           level: StackingLevel,
                           rect: Rect<f32>,
                           clip: ClipRegion,
                           box_bounds: Rect<f32>,
                           offset: Point2D<f32>,
                           color: ColorF,
                           blur_radius: f32,
                           spread_radius: f32,
                           border_radius: f32,
                           clip_mode: BoxShadowClipMode) {
        let item = BoxShadowDisplayItem {
            box_bounds: box_bounds,
            offset: offset,
            color: color,
            blur_radius: blur_radius,
            spread_radius: spread_radius,
            border_radius: border_radius,
            clip_mode: clip_mode,
        };

        let display_item = DisplayItem {
            item: SpecificDisplayItem::BoxShadow(item),
            rect: rect,
            clip: clip,
        };

        self.push_item(level, display_item);
    }

    pub fn push_stacking_context(&mut self,
                                 level: StackingLevel,
                                 stacking_context_id: StackingContextId) {
        self.has_stacking_contexts = true;
        self.flush_list(level);
        let info = StackingContextInfo {
            id: stacking_context_id,
        };
        let item = DisplayListItem {
            stacking_level: level,
            specific: SpecificDisplayListItem::StackingContext(info),
        };
        self.items.push(item);
    }

    pub fn push_gradient(&mut self,
                         level: StackingLevel,
                         rect: Rect<f32>,
                         clip: ClipRegion,
                         start_point: Point2D<f32>,
                         end_point: Point2D<f32>,
                         stops: Vec<GradientStop>) {
        let item = GradientDisplayItem {
            start_point: start_point,
            end_point: end_point,
            stops: stops,
        };

        let display_item = DisplayItem {
            item: SpecificDisplayItem::Gradient(item),
            rect: rect,
            clip: clip,
        };

        self.push_item(level, display_item);
    }

    pub fn push_iframe(&mut self,
                       level: StackingLevel,
                       rect: Rect<f32>,
                       _clip: ClipRegion,
                       iframe: PipelineId) {
        self.flush_list(level);
        let info = Box::new(IframeInfo {
            id: iframe,
            offset: rect.origin,
            clip: rect,
        });
        let item = DisplayListItem {
            stacking_level: level,
            specific: SpecificDisplayListItem::Iframe(info),
        };
        self.items.push(item);
    }

    fn push_item(&mut self, level: StackingLevel, item: DisplayItem) {
        match level {
            StackingLevel::BackgroundAndBorders => {
                self.work_background_and_borders.push(item);
            }
            StackingLevel::BlockBackgroundAndBorders => {
                self.work_block_backgrounds_and_borders.push(item);
            }
            StackingLevel::Floats => {
                self.work_floats.push(item);
            }
            StackingLevel::Content => {
                self.work_content.push(item);
            }
            StackingLevel::PositionedContent => {
                self.work_positioned_content.push(item);
            }
            StackingLevel::Outlines => {
                self.work_outlines.push(item);
            }
        }
    }

    fn flush_list(&mut self, level: StackingLevel) {
        let list = match level {
            StackingLevel::BackgroundAndBorders => {
                &mut self.work_background_and_borders
            }
            StackingLevel::BlockBackgroundAndBorders => {
                &mut self.work_block_backgrounds_and_borders
            }
            StackingLevel::Floats => {
                &mut self.work_floats
            }
            StackingLevel::Content => {
                &mut self.work_content
            }
            StackingLevel::PositionedContent => {
                &mut self.work_positioned_content
            }
            StackingLevel::Outlines => {
                &mut self.work_outlines
            }
        };

        let items = mem::replace(list, Vec::new());
        if items.len() > 0 {
            let draw_list = DrawListInfo {
                items: items,
            };
            self.items.push(DisplayListItem {
                stacking_level: level,
                specific: SpecificDisplayListItem::DrawList(draw_list),
            });
        }
    }

    fn flush(&mut self) {
        self.flush_list(StackingLevel::BackgroundAndBorders);
        self.flush_list(StackingLevel::BlockBackgroundAndBorders);
        self.flush_list(StackingLevel::Floats);
        self.flush_list(StackingLevel::Content);
        self.flush_list(StackingLevel::PositionedContent);
        self.flush_list(StackingLevel::Outlines);
    }

    pub fn finalize(&mut self) {
        self.flush();
    }
}
<|endoftext|>


<commit_before>use std::io::net::ip::{Ipv4Addr, SocketAddr};

mod libtorresmo {
    extern crate time;

    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::SocketAddr;
    use std::io::IoResult;
    use std::mem::{to_be32, to_be16, transmute};
    use std::rand::random;

    #[allow(dead_code,non_camel_case_types)]
    enum UtpPacketType {
        ST_DATA  = 0,
        ST_FIN   = 1,
        ST_STATE = 2,
        ST_RESET = 3,
        ST_SYN   = 4,
    }

    #[allow(dead_code)]
    struct UtpPacketHeader {
        type_ver: u8, // type: u4, ver: u4
        extension: u8,
        connection_id: u16,
        timestamp_microseconds: u32,
        timestamp_difference_microseconds: u32,
        wnd_size: u32,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpPacketHeader {
        fn bytes(&self) -> &[u8] {
            unsafe {
                let buf: &[u8, ..20] = transmute(self);
                return buf.as_slice();
            }
        }

        fn len(&self) -> uint {
            static HEADER_SIZE: uint = 20;
            return HEADER_SIZE;
        }
    }

    #[allow(dead_code)]
    struct UtpPacket {
        header: UtpPacketHeader,
        payload: Vec<u8>,
    }

    impl UtpPacket {
        /// Constructs a new, empty UtpPacket.
        fn new() -> UtpPacket {
            UtpPacket {
                header: UtpPacketHeader {
                    type_ver: ST_DATA as u8 << 4 | 1,
                    extension: 0,
                    connection_id: 0,
                    timestamp_microseconds: 0,
                    timestamp_difference_microseconds: 0,
                    wnd_size: 0,
                    seq_nr: 0,
                    ack_nr: 0,
                },
                payload: Vec::new(),
            }
        }

        fn bytes(&self) -> Vec<u8> {
            let mut buf: Vec<u8> = Vec::with_capacity(self.len());
            buf.push_all(self.header.bytes());
            buf.push_all(self.payload.as_slice());
            return buf;
        }

        fn len(&self) -> uint {
            self.header.len() + self.payload.len()
        }
    }

    pub struct UtpSocket {
        socket: UdpSocket,
        seq_nr: u16,
    }

    impl UtpSocket {
        pub fn bind(addr: SocketAddr) -> IoResult<UtpSocket> {
            let skt = UdpSocket::bind(addr);
            match skt {
                Ok(x)  => Ok(UtpSocket { socket: x, seq_nr: 1 }),
                Err(e) => Err(e)
            }
        }

        pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> {
            let mut packet = UtpPacket::new();
            packet.payload = Vec::from_slice(buf);
            packet.header.seq_nr = to_be16(self.seq_nr);
            packet.header.connection_id = to_be16(random());
            let t = time::get_time();
            packet.header.timestamp_microseconds = to_be32((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32);

            // Send packet
            let result = self.socket.sendto(packet.bytes().as_slice(), dst);

            self.seq_nr += 1;
            result
        }

        pub fn recvfrom(&mut self, buf: &mut[u8]) -> IoResult<(uint,SocketAddr)> {
            self.socket.recvfrom(buf)
        }
    }

    impl Clone for UtpSocket {
        fn clone(&self) -> UtpSocket {
            UtpSocket {
                socket: self.socket.clone(),
                seq_nr: self.seq_nr,
            }
        }
    }

    #[allow(dead_code)]
    struct UtpStream {
        socket: UdpSocket,
        connected_to: SocketAddr,
        seq_nr: u16,
        ack_nr: u16,
    }

    #[allow(dead_code)]
    impl UtpStream {
        fn new(socket: UdpSocket, conn: SocketAddr) -> UtpStream {
            UtpStream {
                socket: socket,
                connected_to: conn,
                seq_nr: 0,
                ack_nr: 0,
            }
        }

        fn disconnect(self) -> UdpSocket {
            self.socket
        }
    }

    impl Reader for UtpStream {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            match self.socket.recvfrom(buf) {
                Ok((_nread, src)) if src != self.connected_to => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e),
            }
        }
    }
    impl Writer for UtpStream {
        fn write(&mut self, buf: &[u8]) -> IoResult<()> {
            self.socket.sendto(buf, self.connected_to)
        }
    }
}

fn usage() {
    println!("Usage: torresmo [-s|-c] <address> <port>");
}

fn main() {
    use libtorresmo::{UtpSocket};
    use std::from_str::FromStr;

    // Defaults
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

    if args.len() == 4 {
        let ip = FromStr::from_str(args.get(2).as_slice()).unwrap();
        let port = FromStr::from_str(args.get(3).as_slice()).unwrap();
        addr = SocketAddr { ip: ip, port: port };
    }

    match args.get(1).as_slice() {
        "-s" => {
            let mut buf = [0, ..512];
            let sock = UtpSocket::bind(addr).unwrap();
            println!("Serving on {}", addr);

            loop {
                let mut sock = sock.clone();
                match sock.recvfrom(buf) {
                    Ok((_, src)) => {
                        spawn(proc() {
                            let mut sock = sock;
                            let payload = String::from_str("Hello\n").into_bytes();

                            // Send uTP packet
                            let _ = sock.sendto(payload.as_slice(), src);
                        })
                    }
                    Err(_) => {}
                }
            }
        }
        "-c" => {
            let mut sock = UtpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: std::rand::random() }).unwrap();
            let _ = sock.sendto([0], addr);
            drop(sock);
        }
        _ => usage(),
    }
}
<commit_msg>Completely replace UtpSocket with UdpStream.<commit_after>use std::io::net::ip::{Ipv4Addr, SocketAddr};

mod libtorresmo {
    extern crate time;

    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::SocketAddr;
    use std::io::IoResult;
    use std::mem::{to_be32, to_be16, transmute};
    use std::rand::random;

    #[allow(dead_code,non_camel_case_types)]
    enum UtpPacketType {
        ST_DATA  = 0,
        ST_FIN   = 1,
        ST_STATE = 2,
        ST_RESET = 3,
        ST_SYN   = 4,
    }

    #[allow(dead_code)]
    struct UtpPacketHeader {
        type_ver: u8, // type: u4, ver: u4
        extension: u8,
        connection_id: u16,
        timestamp_microseconds: u32,
        timestamp_difference_microseconds: u32,
        wnd_size: u32,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpPacketHeader {
        fn bytes(&self) -> &[u8] {
            unsafe {
                let buf: &[u8, ..20] = transmute(self);
                return buf.as_slice();
            }
        }

        fn len(&self) -> uint {
            static HEADER_SIZE: uint = 20;
            return HEADER_SIZE;
        }
    }

    #[allow(dead_code)]
    struct UtpPacket {
        header: UtpPacketHeader,
        payload: Vec<u8>,
    }

    impl UtpPacket {
        /// Constructs a new, empty UtpPacket.
        fn new() -> UtpPacket {
            UtpPacket {
                header: UtpPacketHeader {
                    type_ver: ST_DATA as u8 << 4 | 1,
                    extension: 0,
                    connection_id: 0,
                    timestamp_microseconds: 0,
                    timestamp_difference_microseconds: 0,
                    wnd_size: 0,
                    seq_nr: 0,
                    ack_nr: 0,
                },
                payload: Vec::new(),
            }
        }

        fn bytes(&self) -> Vec<u8> {
            let mut buf: Vec<u8> = Vec::with_capacity(self.len());
            buf.push_all(self.header.bytes());
            buf.push_all(self.payload.as_slice());
            return buf;
        }

        fn len(&self) -> uint {
            self.header.len() + self.payload.len()
        }
    }

    #[allow(dead_code)]
    pub struct UtpStream {
        socket: UdpSocket,
        connected_to: SocketAddr,
        seq_nr: u16,
        ack_nr: u16,
    }

    #[allow(dead_code)]
    impl UtpStream {
        pub fn new(socket: UdpSocket, conn: SocketAddr) -> UtpStream {
            UtpStream {
                socket: socket,
                connected_to: conn,
                seq_nr: 0,
                ack_nr: 0,
            }
        }

        pub fn disconnect(self) -> UdpSocket {
            self.socket
        }
    }

    impl Reader for UtpStream {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            match self.socket.recvfrom(buf) {
                Ok((_nread, src)) if src != self.connected_to => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e),
            }
        }
    }
    impl Writer for UtpStream {
        fn write(&mut self, buf: &[u8]) -> IoResult<()> {
            let mut packet = UtpPacket::new();
            packet.payload = Vec::from_slice(buf);
            packet.header.seq_nr = to_be16(self.seq_nr);
            packet.header.connection_id = to_be16(random());
            let t = time::get_time();
            packet.header.timestamp_microseconds = to_be32((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32);

            // Send packet
            let result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;
            result
        }
    }
}

fn usage() {
    println!("Usage: torresmo [-s|-c] <address> <port>");
}

fn main() {
    use std::io::net::udp::UdpSocket;
    use libtorresmo::UtpStream;
    use std::from_str::FromStr;

    // Defaults
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

    if args.len() == 4 {
        let ip = FromStr::from_str(args.get(2).as_slice()).unwrap();
        let port = FromStr::from_str(args.get(3).as_slice()).unwrap();
        addr = SocketAddr { ip: ip, port: port };
    }

    match args.get(1).as_slice() {
        "-s" => {
            let mut buf = [0, ..512];
            let sock = UdpSocket::bind(addr).unwrap();
            println!("Serving on {}", addr);

            loop {
                let mut sock = sock.clone();
                match sock.recvfrom(buf) {
                    Ok((_, src)) => {
                        spawn(proc() {
                            let mut stream = UtpStream::new(sock, src);
                            let payload = String::from_str("Hello\n").into_bytes();

                            // Send uTP packet
                            let _ = stream.write(payload.as_slice());
                        })
                    }
                    Err(_) => {}
                }
            }
        }
        "-c" => {
            let sock = UdpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: std::rand::random() }).unwrap();
            let mut stream = UtpStream::new(sock, addr);
            let _ = stream.write([0]);
            drop(stream);
        }
        _ => usage(),
    }
}
<|endoftext|>


<commit_before>extern crate clingo;

use std::env;
use clingo::*;

pub struct OnStatementData<'a> {
    atom: ast::Term,
    builder: &'a mut ProgramBuilder,
}

struct MyAstHandler;
impl<'a> AstStatementHandler<OnStatementData<'a>> for MyAstHandler {
    // adds atom enable to all rule bodies
    fn on_statement(stm: &AstStatement, data: &mut OnStatementData) -> bool {
        // pass through all statements that are not rules
        if stm.statement_type() != ast::StatementType::Rule {
            data.builder
                .add(stm)
                .expect("Failed to add statement to ProgramBuilder.");
            return true;
        }

        // copy the current rule body
        let body = unsafe { stm.rule() }.body();
        let mut extended_body = std::vec::Vec::with_capacity(body.len() + 1);
        for e in body {
            extended_body.push(e.clone());
        }

        // create atom enable
        let lit = ast::Literal::new(
            data.atom.location(),
            ast::Sign::None,
            ast::LiteralType::Symbolic,
            &data.atom,
        );
        // add atom enable to the rule body
        let y = ast::BodyLiteral::new(
            data.atom.location(),
            ast::Sign::None,
            ast::BodyLiteralType::Literal,
            &lit,
        );
        extended_body.push(y);

        // initialize the rule
        let head = unsafe { stm.rule() }.head();
        let rule = ast::Rule::new(head, &extended_body);

        // initialize the statement
        let stm2 = AstStatement::new_rule(stm.location(), &rule);

        // add the rewritten statement to the program
        data.builder
            .add(&stm2)
            .expect("Failed to add statement to ProgramBuilder.");
        true
    }
}

fn print_model(model: &mut Model) {
    // retrieve the symbols in the model
    let atoms = model
        .symbols(&ShowType::SHOWN)
        .expect("Failed to retrieve symbols in the model.");

    print!("Model:");

    for atom in atoms {
        // retrieve and print the symbol's string
        print!(" {}", atom.to_string().unwrap());
    }
    println!();
}

fn solve(ctl: &mut Control) {
    // get a solve handle
    let handle = ctl.solve(&SolveMode::YIELD, &[])
        .expect("Failed retrieving solve handle.");

    // loop over all models
    loop {
        handle.resume().expect("Failed resume on solve handle.");
        match handle.model() {
            // print the model
            Ok(model) => print_model(model),
            // stop if there are no more models
            Err(_) => break,
        }
    }

    // close the solve handle
    handle
        .get()
        .expect("Failed to get result from solve handle.");
    handle.close().expect("Failed to close solve handle.");
}

fn main() {
    // collect clingo options from the command line
    let options = env::args().skip(1).collect();

    let mut ctl = Control::new(options, 20).expect("Failed creating Control.");

    let sym = Symbol::create_id("enable", true).unwrap();

    {
        // get the program builder
        let builder = ctl.program_builder().unwrap();

        // begin building a program
        builder.begin().expect("Failed building logic program.");

        // initialize the location
        let location = create_location(0, 0, 0, 0, "<rewrite>", "<rewrite>");

        // initilize atom to add
        let atom = ast::Term::new_symbol(location, sym);

        let mut data = OnStatementData {
            atom: atom,
            builder: builder,
        };

        // get the AST of the program
        parse_program("a :- not b. b :- not a.", &MyAstHandler, &mut data)
            .expect("Failed to parse logic program.");

        // add the external statement: #external enable.
        let ext = ast::External::new(atom, &[]);

        let stm = AstStatement::new_external(location, ast::StatementType::External, &ext);
        data.builder
            .add(&stm)
            .expect("Failed to add statement to ProgramBuilder.");

        // finish building a program
        data.builder
            .end()
            .expect("Failed to finish building a program.");
    }

    // ground the base part
    let part = Part::new("base", &[]);
    let parts = vec![part];
    ctl.ground(&parts)
        .expect("Failed to ground a logic program.");

    // solve with external enable = false
    println!("Solving with enable = false...");
    solve(&mut ctl);

    // solve with external enable = true
    println!("Solving with enable = true...");
    ctl.assign_external(&sym, TruthValue::True)
        .expect("Failed to assign #external enable true.");
    solve(&mut ctl);

    // solve with external enable = false
    println!("Solving with enable = false...");
    ctl.assign_external(&sym, TruthValue::False)
        .expect("Failed to assign #external enable false.");
    solve(&mut ctl);
}
<commit_msg>rename create_location() to Location::new()<commit_after>extern crate clingo;

use std::env;
use clingo::*;

pub struct OnStatementData<'a> {
    atom: ast::Term,
    builder: &'a mut ProgramBuilder,
}

struct MyAstHandler;
impl<'a> AstStatementHandler<OnStatementData<'a>> for MyAstHandler {
    // adds atom enable to all rule bodies
    fn on_statement(stm: &AstStatement, data: &mut OnStatementData) -> bool {
        // pass through all statements that are not rules
        if stm.statement_type() != ast::StatementType::Rule {
            data.builder
                .add(stm)
                .expect("Failed to add statement to ProgramBuilder.");
            return true;
        }

        // copy the current rule body
        let body = unsafe { stm.rule() }.body();
        let mut extended_body = std::vec::Vec::with_capacity(body.len() + 1);
        for e in body {
            extended_body.push(e.clone());
        }

        // create atom enable
        let lit = ast::Literal::new(
            data.atom.location(),
            ast::Sign::None,
            ast::LiteralType::Symbolic,
            &data.atom,
        );
        // add atom enable to the rule body
        let y = ast::BodyLiteral::new(
            data.atom.location(),
            ast::Sign::None,
            ast::BodyLiteralType::Literal,
            &lit,
        );
        extended_body.push(y);

        // initialize the rule
        let head = unsafe { stm.rule() }.head();
        let rule = ast::Rule::new(head, &extended_body);

        // initialize the statement
        let stm2 = AstStatement::new_rule(stm.location(), &rule);

        // add the rewritten statement to the program
        data.builder
            .add(&stm2)
            .expect("Failed to add statement to ProgramBuilder.");
        true
    }
}

fn print_model(model: &mut Model) {
    // retrieve the symbols in the model
    let atoms = model
        .symbols(&ShowType::SHOWN)
        .expect("Failed to retrieve symbols in the model.");

    print!("Model:");

    for atom in atoms {
        // retrieve and print the symbol's string
        print!(" {}", atom.to_string().unwrap());
    }
    println!();
}

fn solve(ctl: &mut Control) {
    // get a solve handle
    let handle = ctl.solve(&SolveMode::YIELD, &[])
        .expect("Failed retrieving solve handle.");

    // loop over all models
    loop {
        handle.resume().expect("Failed resume on solve handle.");
        match handle.model() {
            // print the model
            Ok(model) => print_model(model),
            // stop if there are no more models
            Err(_) => break,
        }
    }

    // close the solve handle
    handle
        .get()
        .expect("Failed to get result from solve handle.");
    handle.close().expect("Failed to close solve handle.");
}

fn main() {
    // collect clingo options from the command line
    let options = env::args().skip(1).collect();

    let mut ctl = Control::new(options, 20).expect("Failed creating Control.");

    let sym = Symbol::create_id("enable", true).unwrap();

    {
        // get the program builder
        let builder = ctl.program_builder().unwrap();

        // begin building a program
        builder.begin().expect("Failed building logic program.");

        // initialize the location
        let location = Location::new(0, 0, 0, 0, "<rewrite>", "<rewrite>");

        // initilize atom to add
        let atom = ast::Term::new_symbol(location, sym);

        let mut data = OnStatementData {
            atom: atom,
            builder: builder,
        };

        // get the AST of the program
        parse_program("a :- not b. b :- not a.", &MyAstHandler, &mut data)
            .expect("Failed to parse logic program.");

        // add the external statement: #external enable.
        let ext = ast::External::new(atom, &[]);

        let stm = AstStatement::new_external(location, ast::StatementType::External, &ext);
        data.builder
            .add(&stm)
            .expect("Failed to add statement to ProgramBuilder.");

        // finish building a program
        data.builder
            .end()
            .expect("Failed to finish building a program.");
    }

    // ground the base part
    let part = Part::new("base", &[]);
    let parts = vec![part];
    ctl.ground(&parts)
        .expect("Failed to ground a logic program.");

    // solve with external enable = false
    println!("Solving with enable = false...");
    solve(&mut ctl);

    // solve with external enable = true
    println!("Solving with enable = true...");
    ctl.assign_external(&sym, TruthValue::True)
        .expect("Failed to assign #external enable true.");
    solve(&mut ctl);

    // solve with external enable = false
    println!("Solving with enable = false...");
    ctl.assign_external(&sym, TruthValue::False)
        .expect("Failed to assign #external enable false.");
    solve(&mut ctl);
}
<|endoftext|>


<commit_before>use std::io;
use std::process::Command;
use std::sync::Arc;

use futures::future;
use futures::prelude::*;
use futures::sync::mpsc;
use futures::sync::oneshot;

use crate::errors::*;

#[derive(Clone)]
pub struct Client {
    helper: Option<Arc<jobserver::HelperThread>>,
    tx: Option<mpsc::UnboundedSender<oneshot::Sender<io::Result<jobserver::Acquired>>>>,
    inner: jobserver::Client,
}

pub struct Acquired {
    _token: Option<jobserver::Acquired>,
}

impl Client {
    // unsafe because `from_env` is unsafe (can use the wrong fds)
    pub unsafe fn new() -> Client {
        match jobserver::Client::from_env() {
            Some(c) => Client::_new(c, true),
            None => Client::new_num(num_cpus::get()),
        }
    }

    pub fn new_num(num: usize) -> Client {
        let inner = jobserver::Client::new(num).expect("failed to create jobserver");
        Client::_new(inner, false)
    }

    fn _new(inner: jobserver::Client, inherited: bool) -> Client {
        let (helper, tx) = if inherited {
            (None, None)
        } else {
            let (tx, rx) = mpsc::unbounded::<oneshot::Sender<_>>();
            let mut rx = rx.wait();
            let helper = inner
                .clone()
                .into_helper_thread(move |token| {
                    if let Some(Ok(sender)) = rx.next() {
                        drop(sender.send(token));
                    }
                })
                .expect("failed to spawn helper thread");
            (Some(Arc::new(helper)), Some(tx))
        };

        Client { inner, helper, tx }
    }

    /// Configures this jobserver to be inherited by the specified command
    pub fn configure(&self, cmd: &mut Command) {
        self.inner.configure(cmd)
    }

    /// Returns a future that represents an acquired jobserver token.
    ///
    /// This should be invoked before any "work" is spawend (for whatever the
    /// defnition of "work" is) to ensure that the system is properly
    /// rate-limiting itself.
    pub fn acquire(&self) -> SFuture<Acquired> {
        let (helper, tx) = match (self.helper.as_ref(), self.tx.as_ref()) {
            (Some(a), Some(b)) => (a, b),
            _ => return Box::new(future::ok(Acquired { _token: None })),
        };
        let (mytx, myrx) = oneshot::channel();
        helper.request_token();
        tx.unbounded_send(mytx).unwrap();
        Box::new(
            myrx.chain_err(|| "jobserver helper panicked")
                .and_then(|t| t.chain_err(|| "failed to acquire jobserver token"))
                .map(|t| Acquired { _token: Some(t) }),
        )
    }
}
<commit_msg>fix typos in jobserver.rs<commit_after>use std::io;
use std::process::Command;
use std::sync::Arc;

use futures::future;
use futures::prelude::*;
use futures::sync::mpsc;
use futures::sync::oneshot;

use crate::errors::*;

#[derive(Clone)]
pub struct Client {
    helper: Option<Arc<jobserver::HelperThread>>,
    tx: Option<mpsc::UnboundedSender<oneshot::Sender<io::Result<jobserver::Acquired>>>>,
    inner: jobserver::Client,
}

pub struct Acquired {
    _token: Option<jobserver::Acquired>,
}

impl Client {
    // unsafe because `from_env` is unsafe (can use the wrong fds)
    pub unsafe fn new() -> Client {
        match jobserver::Client::from_env() {
            Some(c) => Client::_new(c, true),
            None => Client::new_num(num_cpus::get()),
        }
    }

    pub fn new_num(num: usize) -> Client {
        let inner = jobserver::Client::new(num).expect("failed to create jobserver");
        Client::_new(inner, false)
    }

    fn _new(inner: jobserver::Client, inherited: bool) -> Client {
        let (helper, tx) = if inherited {
            (None, None)
        } else {
            let (tx, rx) = mpsc::unbounded::<oneshot::Sender<_>>();
            let mut rx = rx.wait();
            let helper = inner
                .clone()
                .into_helper_thread(move |token| {
                    if let Some(Ok(sender)) = rx.next() {
                        drop(sender.send(token));
                    }
                })
                .expect("failed to spawn helper thread");
            (Some(Arc::new(helper)), Some(tx))
        };

        Client { inner, helper, tx }
    }

    /// Configures this jobserver to be inherited by the specified command
    pub fn configure(&self, cmd: &mut Command) {
        self.inner.configure(cmd)
    }

    /// Returns a future that represents an acquired jobserver token.
    ///
    /// This should be invoked before any "work" is spawned (for whatever the
    /// definition of "work" is) to ensure that the system is properly
    /// rate-limiting itself.
    pub fn acquire(&self) -> SFuture<Acquired> {
        let (helper, tx) = match (self.helper.as_ref(), self.tx.as_ref()) {
            (Some(a), Some(b)) => (a, b),
            _ => return Box::new(future::ok(Acquired { _token: None })),
        };
        let (mytx, myrx) = oneshot::channel();
        helper.request_token();
        tx.unbounded_send(mytx).unwrap();
        Box::new(
            myrx.chain_err(|| "jobserver helper panicked")
                .and_then(|t| t.chain_err(|| "failed to acquire jobserver token"))
                .map(|t| Acquired { _token: Some(t) }),
        )
    }
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;
extern mod native;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdio::stdin;
use std::run::{Process, ProcessOptions};
use std::io::{File, Open, Read, Write};
use std::path::posix::Path;
use std::libc::{fileno, fopen, pid_t, c_int};
use std::libc;
use std::io::signal::{Listener, Interrupt};
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    working_directory: Path,
    history: ~[~str],
    output_redirects: ~[~str]
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            working_directory: Path::new(os::getcwd()),
            history: ~[],
            output_redirects: ~[]
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());
        // println!("PWD: {}", self.working_directory.display() );
        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();

            // Add this command to the history
            self.add_to_history(cmd_line.clone());

            // for &x in ins.iter() {
            //     println!("Elem {}", x);
            // }

            // Check to see if there are any output redirects
            // if cmd_line.contains(">") {
            //     let mut split : ~[&str] = cmd_line.split('>').collect();
            //     split.remove(0);
            //     let mut split2 = ~[];
            //     for x in split.iter() {
            //         split2.push(x.to_owned());
            //     }
            //     self.output_redirects = split2;
            // }

            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn get_output_redirects(&mut self, cmd_line: &str) -> ~[&str] {
        /*
        *   Get the output redirect filenames designated by >
        */
        let mut output_files : ~[&str] = ~[];
        if cmd_line.contains(">") {
            let mut files: ~[&str] = cmd_line.split('>').collect();
            files.remove(0);
            output_files = files.clone();
        }
        return output_files;
    }

    fn get_input_redirect(&mut self, cmd_line: &str) -> ~[&str] {
        let mut input_files : ~[&str] = ~[];
        if cmd_line.contains("<") {
            let mut files: ~[&str] = cmd_line.split('<').collect();
            files.remove(0);
            for elem in files.iter() {
                if elem.contains(">") {
                    let mut outs: ~[&str] = elem.split('>').collect();
                    let inputf : &str = outs[0];
                    input_files.push(inputf.trim());
                } else {
                    input_files.push(elem.trim());
                }
            }
        }
        input_files
    }

    fn get_pipes(&mut self, cmd_line: &str) -> ~[&str] {
        let mut pipes : ~[&str] = ~[];
        if cmd_line.contains("|") {
            let mut temp : ~[&str] = cmd_line.split('|').collect();
            temp.remove(0);
            pipes = temp.clone();
        }
        pipes
    }

    fn add_to_history(&mut self, cmd_line: ~str) {
        if cmd_line != ~"" {
            self.history.push(cmd_line);
        }
    }

    fn print_history(&mut self) {
        let mut count = 0;
        for x in self.history.iter() {
            println!("  {} {}",count, *x);
            count += 1;
        }
    }

    fn should_run_in_background(&mut self, cmd_line: &str) -> bool {
        // Check to see if we should be running in the background
        let mut run_in_background : bool = false;
        if cmd_line.contains("&") {
            run_in_background = true;
        }
        run_in_background
    }

    fn change_directory(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            // Remove the "cd" argument
            argv.remove(0);
            if argv.len() > 0 {
                self.working_directory.push(argv.remove(0));
            } else {
                self.working_directory = os::homedir().unwrap()
            }
            // println!("Changing directory to: {}", self.working_directory.display());
            os::change_dir(&self.working_directory);
            // println!("CWD: {}", self.working_directory.display());
        }
    }

    fn run_cmdline_in_background(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        // Remove & from argument list
        let mut ind = -1;
        let mut count = 0;
        for x in argv.iter() {
            if *x == ~"&" {
                ind = count;
            }
            count += 1;
        }
        argv.remove(ind);

        // let (port, chan): (Port<int>, Chan<int>) = Chan::new();

        println("[1]");

        if( argv[0] == ~"cd" ) {
            if argv.len() > 0 {
                argv.remove(0);
                if argv.len() > 0 {
                    self.working_directory.push(argv.remove(0));
                } else {
                    self.working_directory = os::homedir().unwrap()
                }
                let working_dir = self.working_directory.clone();
                spawn(proc() {
                    os::change_dir(&working_dir);
                } );
            }
        } else if( argv[0] == ~"history" ) {
            let hist : ~[~str] = self.history.clone();

            spawn( proc() {
                let mut count = 0;
                for x in hist.iter() {
                    println!("  {} {}",count, *x);
                    count += 1;
                }});
        } else if argv.len() > 0 {
            let prog: ~str = argv.remove(0);
            let args: ~[~str] = argv.clone();
            // fn call(f: |~str, ~[~str]|) { |prog, args| println!("Program={}, args={}", prog, args); }
            // let closure = |prog, args| println!("Program={}, args={}", prog, args);

            spawn( proc() {

                fn cmd_exists(cmd_path: &str) -> bool {
                    let ret = run::process_output("which", [cmd_path.to_owned()]);
                    return ret.expect("exit code error.").status.success();
                }

                for x in args.iter() {
                    print(x.clone())
                }
                // println("");
                if cmd_exists(prog) {
                    run::process_status(prog, args);
                } else {
                    println!("{:s}: command not found", prog);
                }
                // chan.send(1);
            });
        }
        // println!("[{:d}] Done",port.recv());

        // println("Done Executing Task");
    }

    fn run_cmdline(&mut self, cmd_line: &str) {

        // Check to see if we should be running in the background
        let run_in_background : bool = self.should_run_in_background(cmd_line.clone());
        let output_redirects = self.get_output_redirects(cmd_line);
        let input_redirects : ~[&str] = self.get_input_redirect(cmd_line);

        if run_in_background {
            self.run_cmdline_in_background(cmd_line.clone());
        }
        else if input_redirects.len() > 0 {
            let temp_split : ~[&str] = cmd_line.split('<').collect();
            let cmd_line_sans_redirects = temp_split[0];
            let mut argv: ~[~str] =
                cmd_line_sans_redirects.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

            if argv.len() > 0 {
                let program: ~str = argv.remove(0);
                self.run_cmd_with_input_redirect(program, argv, input_redirects);
            }
        }
        else if output_redirects.len() > 0 {
            // Need to first create the output files if they do not exist
            for &file in output_redirects.iter() {
                // Trim the filename to get rid of weird whitespace bugs
                let path: Path = Path::new(file.trim());
                if !path.is_file() {
                    File::create(&path);
                }
            }

            // Get the program and args.. We do not want the things after > as that will cause errors
            let temp_split : ~[&str] = cmd_line.split('>').collect();
            let cmd_line_sans_redirects = temp_split[0];
            let mut argv: ~[~str] =
                cmd_line_sans_redirects.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

            if argv.len() > 0 {
                let program: ~str = argv.remove(0);
                self.run_cmd_with_output_redirect(program, argv, output_redirects);
            }
        }
        else {
            let mut argv: ~[~str] =
                cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

            if( argv[0] == ~"cd" ) {
                self.change_directory(cmd_line);
            } else if( argv[0] == ~"history" ) {
                self.print_history();
            } else if argv.len() > 0 {
                let program: ~str = argv.remove(0);
                self.run_cmd(program, argv);
            }
        }
    }

    fn run_cmd_with_output_redirect(&mut self, program: &str, argv: &[~str], output_files: ~[&str]) {
        if self.cmd_exists(program) {
            let write_to_file : &str = output_files[output_files.len()-1].trim();
            let f = match native::io::file::open(&write_to_file.to_c_str(), Open, Write) {
                Ok(f)   => f,
                Err(e)  => { fail!("Could not open output file") }
            };
            let file_descriptor = f.fd();

            let mut process = run::Process::new(program, argv, run::ProcessOptions {
                env: None,
                dir: None,
                in_fd: Some(unsafe { libc::dup(libc::STDIN_FILENO) }),
                out_fd: Some(file_descriptor),
                err_fd: Some(unsafe { libc::dup(libc::STDERR_FILENO) })
            });

            // process.finish();
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cmd_with_input_redirect(&mut self, program: &str, argv: &[~str], input_files: ~[&str]) {
        if self.cmd_exists(program) {
            let read_from_file : &str = input_files[input_files.len()-1].trim();
            let f = match native::io::file::open(&read_from_file.to_c_str(), Open, Read) {
                Ok(f)   => f,
                Err(e)  => fail!("Problem opening file")
            };
            let file_descriptor = f.fd();

            let mut process = run::Process::new(program, argv, run::ProcessOptions {
                env: None,
                dir: None,
                in_fd: Some(file_descriptor),
                out_fd: Some(unsafe { libc::dup(libc::STDOUT_FILENO) }),
                err_fd: Some(unsafe { libc::dup(libc::STDERR_FILENO) })
            });
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        // println!("Program: {:s}", program);
        // print("Has args: ");

        // for x in argv.iter() {
        //     print(x.clone())
        // }

        // println("");
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        // println!("Checking if command {:s} exists", cmd_path);
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn handle_interrupt() {
    let mut l = Listener::new();
    l.register(Interrupt);

    let l_copy = l;
    spawn(proc() {
        loop {
            match l_copy.port.recv() {
                Interrupt => continue,
                _         => ()
            }
        }
    });
}

fn main() {
    handle_interrupt();

    let opt_cmd_line = get_cmdline_from_args();
    match opt_cmd_line {
        Some(cmd_line) => { println!("Command: {:s}", cmd_line); Shell::new("").run_cmdline(cmd_line) },
        None           => { Shell::new("gash > ").run() }
    }
}
<commit_msg>Submission v1<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;
extern mod native;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdio::stdin;
use std::run::{Process, ProcessOptions};
use std::io::{File, Open, Read, Write};
use std::path::posix::Path;
use std::libc;
use std::str;
use std::io::signal::{Listener, Interrupt};
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    working_directory: Path,
    history: ~[~str],
    output_redirects: ~[~str]
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            working_directory: Path::new(os::getcwd()),
            history: ~[],
            output_redirects: ~[]
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());
        // println!("PWD: {}", self.working_directory.display() );
        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();

            // Add this command to the history
            self.add_to_history(cmd_line.clone());

            // for &x in ins.iter() {
            //     println!("Elem {}", x);
            // }

            // Check to see if there are any output redirects
            // if cmd_line.contains(">") {
            //     let mut split : ~[&str] = cmd_line.split('>').collect();
            //     split.remove(0);
            //     let mut split2 = ~[];
            //     for x in split.iter() {
            //         split2.push(x.to_owned());
            //     }
            //     self.output_redirects = split2;
            // }

            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn get_output_redirects(&mut self, cmd_line: &str) -> ~[&str] {
        /*
        *   Get the output redirect filenames designated by >
        */
        let mut output_files : ~[&str] = ~[];
        if cmd_line.contains(">") {
            let mut files: ~[&str] = cmd_line.split('>').collect();
            files.remove(0);
            output_files = files.clone();
        }
        return output_files;
    }

    fn get_input_redirect(&mut self, cmd_line: &str) -> ~[&str] {
        let mut input_files : ~[&str] = ~[];
        if cmd_line.contains("<") {
            let mut files: ~[&str] = cmd_line.split('<').collect();
            files.remove(0);
            for elem in files.iter() {
                if elem.contains(">") {
                    let outs: ~[&str] = elem.split('>').collect();
                    let inputf : &str = outs[0];
                    input_files.push(inputf.trim());
                } else {
                    input_files.push(elem.trim());
                }
            }
        }
        input_files
    }

    fn get_pipes(&mut self, cmd_line: &str) -> ~[&str] {
        let mut pipes : ~[&str] = ~[];
        if cmd_line.contains("|") {
            let mut temp : ~[&str] = cmd_line.split('|').collect();
            // temp.remove(0);
            pipes = temp.clone();
        }
        pipes
    }

    fn add_to_history(&mut self, cmd_line: ~str) {
        if cmd_line != ~"" {
            self.history.push(cmd_line);
        }
    }

    fn print_history(&mut self) {
        let mut count = 0;
        for x in self.history.iter() {
            println!("  {} {}",count, *x);
            count += 1;
        }
    }

    fn should_run_in_background(&mut self, cmd_line: &str) -> bool {
        // Check to see if we should be running in the background
        let mut run_in_background : bool = false;
        if cmd_line.contains("&") {
            run_in_background = true;
        }
        run_in_background
    }

    fn change_directory(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            // Remove the "cd" argument
            argv.remove(0);
            if argv.len() > 0 {
                self.working_directory.push(argv.remove(0));
            } else {
                self.working_directory = os::homedir().unwrap()
            }
            // println!("Changing directory to: {}", self.working_directory.display());
            os::change_dir(&self.working_directory);
            // println!("CWD: {}", self.working_directory.display());
        }
    }

    fn run_cmdline_in_background(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        // Remove & from argument list
        let mut ind = -1;
        let mut count = 0;
        for x in argv.iter() {
            if *x == ~"&" {
                ind = count;
            }
            count += 1;
        }
        argv.remove(ind);

        // let (port, chan): (Port<int>, Chan<int>) = Chan::new();

        println("[1]");

        if( argv[0] == ~"cd" ) {
            if argv.len() > 0 {
                argv.remove(0);
                if argv.len() > 0 {
                    self.working_directory.push(argv.remove(0));
                } else {
                    self.working_directory = os::homedir().unwrap()
                }
                let working_dir = self.working_directory.clone();
                spawn(proc() {
                    os::change_dir(&working_dir);
                } );
            }
        } else if( argv[0] == ~"history" ) {
            let hist : ~[~str] = self.history.clone();

            spawn( proc() {
                let mut count = 0;
                for x in hist.iter() {
                    println!("  {} {}",count, *x);
                    count += 1;
                }});
        } else if argv.len() > 0 {
            let prog: ~str = argv.remove(0);
            let args: ~[~str] = argv.clone();
            // fn call(f: |~str, ~[~str]|) { |prog, args| println!("Program={}, args={}", prog, args); }
            // let closure = |prog, args| println!("Program={}, args={}", prog, args);

            spawn( proc() {

                fn cmd_exists(cmd_path: &str) -> bool {
                    let ret = run::process_output("which", [cmd_path.to_owned()]);
                    return ret.expect("exit code error.").status.success();
                }

                for x in args.iter() {
                    print(x.clone())
                }
                // println("");
                if cmd_exists(prog) {
                    run::process_status(prog, args);
                } else {
                    println!("{:s}: command not found", prog);
                }
                // chan.send(1);
            });
        }
        // println!("[{:d}] Done",port.recv());

        // println("Done Executing Task");
    }

    fn run_cmdline(&mut self, cmd_line: &str) {

        // Check to see if we should be running in the background
        let run_in_background : bool = self.should_run_in_background(cmd_line.clone());
        let output_redirects = self.get_output_redirects(cmd_line);
        let input_redirects : ~[&str] = self.get_input_redirect(cmd_line);
        let pipes : ~[&str] = self.get_pipes(cmd_line);

        if run_in_background {
            self.run_cmdline_in_background(cmd_line.clone());
        } else if pipes.len() > 0 {
            let mut pipes_commands = pipes.clone();

            let command = pipes_commands.remove(0).trim();

            let mut argv: ~[~str] =
                command.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
            let program = argv.remove(0);

            // We need to make the output of command be fed into the input of the rest of the
            // argv. This command freezes the output
            let output = run::process_output(program, argv);

            let mut input_to_next_pipe: ~[u8] = ~[];
            for x in output.iter() {
                input_to_next_pipe = x.output.clone();
            }

            self.run_cmd_with_pipes(pipes_commands , input_to_next_pipe);

        }
        else if input_redirects.len() > 0 {
            let temp_split : ~[&str] = cmd_line.split('<').collect();
            let cmd_line_sans_redirects = temp_split[0];
            let mut argv: ~[~str] =
                cmd_line_sans_redirects.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

            if argv.len() > 0 {
                let program: ~str = argv.remove(0);
                self.run_cmd_with_input_redirect(program, argv, input_redirects);
            }
        }
        else if output_redirects.len() > 0 {
            // Need to first create the output files if they do not exist
            for &file in output_redirects.iter() {
                // Trim the filename to get rid of weird whitespace bugs
                let path: Path = Path::new(file.trim());
                if !path.is_file() {
                    File::create(&path);
                }
            }

            // Get the program and args.. We do not want the things after > as that will cause errors
            let temp_split : ~[&str] = cmd_line.split('>').collect();
            let cmd_line_sans_redirects = temp_split[0];
            let mut argv: ~[~str] =
                cmd_line_sans_redirects.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

            if argv.len() > 0 {
                let program: ~str = argv.remove(0);
                self.run_cmd_with_output_redirect(program, argv, output_redirects);
            }
        }
        else {
            let mut argv: ~[~str] =
                cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

            if( argv[0] == ~"cd" ) {
                self.change_directory(cmd_line);
            } else if( argv[0] == ~"history" ) {
                self.print_history();
            } else if argv.len() > 0 {
                let program: ~str = argv.remove(0);
                self.run_cmd(program, argv);
            }
        }
    }

    fn run_cmd_with_output_redirect(&mut self, program: &str, argv: &[~str], output_files: ~[&str]) {
        if self.cmd_exists(program) {
            let write_to_file : &str = output_files[output_files.len()-1].trim();
            let f = match native::io::file::open(&write_to_file.to_c_str(), Open, Write) {
                Ok(f)   => f,
                Err(e)  => { fail!("Could not open output file") }
            };
            let file_descriptor = f.fd();

            let mut process = run::Process::new(program, argv, run::ProcessOptions {
                env: None,
                dir: None,
                in_fd: Some(unsafe { libc::dup(libc::STDIN_FILENO) }),
                out_fd: Some(file_descriptor),
                err_fd: Some(unsafe { libc::dup(libc::STDERR_FILENO) })
            });

            // process.finish();
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cmd_with_input_redirect(&mut self, program: &str, argv: &[~str], input_files: ~[&str]) {
        if self.cmd_exists(program) {
            let read_from_file : &str = input_files[input_files.len()-1].trim();
            let f = match native::io::file::open(&read_from_file.to_c_str(), Open, Read) {
                Ok(f)   => f,
                Err(e)  => fail!("Problem opening file")
            };
            let file_descriptor = f.fd();

            let mut process = run::Process::new(program, argv, run::ProcessOptions {
                env: None,
                dir: None,
                in_fd: Some(file_descriptor),
                out_fd: Some(unsafe { libc::dup(libc::STDOUT_FILENO) }),
                err_fd: Some(unsafe { libc::dup(libc::STDERR_FILENO) })
            });
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cmd_with_pipes(&mut self, mut remaining_commands: ~[&str], input: ~[u8]) {
        // Recursively exhaust the pipes

        if remaining_commands.len() == 0 {
            return;
        }
        let command : &str = remaining_commands.remove(0);
        let mut argv: ~[~str] =
                command.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        let program = argv.remove(0);

        if self.cmd_exists(program) {
            let mut output: ~[u8] = ~[];
            match Process::new(program, argv, ProcessOptions::new()) {
                Some(mut p) => {
                    {
                        let process = &mut p;
                        let writer = process.input();
                        writer.write(input);
                    }

                    let process_output = p.finish_with_output();
                    output = process_output.output.clone();
                },
                None => fail!("Piping Error!")
            }

            if remaining_commands.len() == 0 {
                println!("{}", str::from_utf8(output));
            }
            self.run_cmd_with_pipes(remaining_commands, output);
        }
        else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        // println!("Program: {:s}", program);
        // print("Has args: ");

        // for x in argv.iter() {
        //     print(x.clone())
        // }

        // println("");
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        // println!("Checking if command {:s} exists", cmd_path);
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn handle_interrupt() {
    let mut l = Listener::new();
    l.register(Interrupt);

    let l_copy = l;
    spawn(proc() {
        loop {
            match l_copy.port.recv() {
                Interrupt => continue,
                _         => ()
            }
        }
    });
}

fn main() {
    handle_interrupt();

    let opt_cmd_line = get_cmdline_from_args();
    match opt_cmd_line {
        Some(cmd_line) => { println!("Command: {:s}", cmd_line); Shell::new("").run_cmdline(cmd_line) },
        None           => { Shell::new("gash > ").run() }
    }
}
<|endoftext|>