<commit_before>/// Figure 11.11 Using two mutexes
///
/// Findings:
/// - After wrestling with static mut again realized
///   that fh and hashlock are much better off stuffed into
///   a struct
///
/// Status: only partially implemented

extern crate libc;
use libc::{pthread_mutex_t, PTHREAD_MUTEX_INITIALIZER};
use libc::{pthread_mutex_init, pthread_mutex_lock, pthread_mutex_unlock};
use std::ptr::null;
use std::collections::LinkedList;

const NHASH:usize = 29;
macro_rules! HASH {
    ($i:expr) => {{
        $i % NHASH as i64
    }}
}

struct Foo {
    f_count: i64,
    f_lock: pthread_mutex_t,
    f_id: i64,
}

struct Hashmap {
    fh:Vec<LinkedList<Foo>>,
    hashlock:pthread_mutex_t,
}

impl Hashmap {
    fn new() -> Hashmap {
        let mut fh = Vec::with_capacity(NHASH);
        for i in 0..NHASH {
            fh[i] = LinkedList::new();
        }
        Hashmap{fh:fh, hashlock: PTHREAD_MUTEX_INITIALIZER}
    }

    fn foo_alloc(&mut self, id: i64) -> Option<&Foo> {
        // allocate the object
        unsafe {
            let mut foo = Foo { f_count: 1, f_lock: std::mem::zeroed(), f_id: id};
            if pthread_mutex_init(&mut foo.f_lock, null()) != 0 {
                // does not need free as foo is dropped upon return
                return None
            }
            let idx = HASH!(id);
            pthread_mutex_lock(&mut self.hashlock);
            let mut ll = &mut self.fh[idx as usize];
            ll.push_back(foo);
            pthread_mutex_lock(&mut ll.front_mut().unwrap().f_lock);
            pthread_mutex_unlock(&mut self.hashlock);
            // continue initialization
            pthread_mutex_unlock(&mut ll.front_mut().unwrap().f_lock);
            Some(&foo)
        }
    }
}

fn main() {

}

<commit_msg>Finally finished Figure 11.11<commit_after>#![allow(dead_code)]
/// Figure 11.11 Using two mutexes
///
/// Of course, you would not reimplement this as Rust has Arc and Mutex
/// which would make the whole excercise boil down to <10 lines
///
/// Findings:
/// - After wrestling with static mut again realized
///   that fh and hashlock are much better off stuffed into
///   a struct
/// - After wrestling with lifetimes (especially in `foo_alloc`)
///   and opening http://stackoverflow.com/questions/42392250
///   it was quite easy and uses no explicit lifetimes (all lifetimes
///   are alluded)
/// - removing elements from linked lists is not supported by the
///   std lib even though I can't see why it wouldn't (as it's basically
///   the same as `remove` in the Vec)
///
/// Status: compiles, not tested. I'd especially like to see if/how
/// the freeing of foo in `rele` works

extern crate libc;
use libc::{pthread_mutex_t, PTHREAD_MUTEX_INITIALIZER};
use libc::{pthread_mutex_init, pthread_mutex_lock, pthread_mutex_unlock, pthread_mutex_destroy};
use std::ptr::null;
use std::collections::LinkedList;

const NHASH:i64 = 29;
macro_rules! HASH {
    ($i:expr) => {{
        ($i % NHASH) as usize
    }}
}

struct Foo {
    f_count: i64,
    f_lock: pthread_mutex_t,
    f_id: i64,
}

struct Hashmap {
    fh:Vec<LinkedList<Foo>>,
    hashlock:pthread_mutex_t,
}

impl Hashmap {
    fn new() -> Hashmap {
        let mut fh = Vec::with_capacity(NHASH as usize);
        for i in 0..fh.len() {
            fh[i] = LinkedList::new();
        }
        Hashmap{fh:fh, hashlock: PTHREAD_MUTEX_INITIALIZER}
    }

    fn foo_alloc(&mut self, id: i64) -> Option<&mut Foo> {
        unsafe {
            let mut foo = Foo { f_count: 1, f_lock: std::mem::zeroed(), f_id: id};
            if pthread_mutex_init(&mut foo.f_lock, null()) != 0 {
                // does not need free as foo is dropped upon return
                return None
            }
            pthread_mutex_lock(&mut self.hashlock);
            let mut ll = &mut self.fh[HASH!(id)];
            ll.push_back(foo);
            pthread_mutex_lock(&mut ll.front_mut().unwrap().f_lock);
            pthread_mutex_unlock(&mut self.hashlock);
            // continue initialization
            pthread_mutex_unlock(&mut ll.front_mut().unwrap().f_lock);
            ll.front_mut()
        }
    }

    fn foo_hold(foo:&mut Foo) {
        unsafe {
            pthread_mutex_lock(&mut foo.f_lock);
            foo.f_count += 1;
            pthread_mutex_unlock(&mut foo.f_lock);
        }
    }

    fn foo_find(&mut self, id: i64) -> Option<&mut Foo> {
        unsafe {
            pthread_mutex_lock(&mut self.hashlock);
            for mut foo in &mut self.fh[HASH!(id)] {
                if foo.f_id == id {
                    Hashmap::foo_hold(&mut foo);
                    pthread_mutex_unlock(&mut self.hashlock);
                    return Some(foo);
                }
            }
            pthread_mutex_unlock(&mut self.hashlock);
            None
        }
    }

    fn foo_rele(&mut self, foo:&mut Foo) {
        unsafe {
            pthread_mutex_lock(&mut foo.f_lock);
            if foo.f_count == 1 {
                pthread_mutex_unlock(&mut foo.f_lock);
                pthread_mutex_lock(&mut self.hashlock);
                pthread_mutex_lock(&mut foo.f_lock);
                // need to recheck the condition
                if foo.f_count != 1 {
                    foo.f_count -= 1;
                    pthread_mutex_unlock(&mut foo.f_lock);
                    pthread_mutex_unlock(&mut self.hashlock);
                    return
                }
                let ll = self.fh.remove(HASH!(foo.f_id));
                // iter.filter() is probably best way to remove an element from a linked list
                // see https://www.reddit.com/r/rust/comments/33g3ek
                self.fh[HASH!(foo.f_id)] = ll.into_iter().filter(|f| f.f_id != foo.f_id).collect();
                pthread_mutex_unlock(&mut self.hashlock);
                pthread_mutex_unlock(&mut foo.f_lock);
                pthread_mutex_destroy(&mut foo.f_lock);
            } else {
                foo.f_count -= 1;
                pthread_mutex_unlock(&mut foo.f_lock);
            }
        }
    }
}

fn main() {

}<|endoftext|>


<commit_before>use subframe;
use subframe::{Subframe, MAX_FIXED_ORDER, MAX_LPC_ORDER};

use std::ptr;

pub fn fixed_restore_signal(order: usize,
                            residual: &[i32],
                            output: &mut [i32]) {
  debug_assert!(order <= MAX_FIXED_ORDER);

  let polynomial = [ &[][..]
                   , &[1][..]
                   , &[-1, 2][..]
                   , &[1, -3, 3][..]
                   , &[-1, 4, -6, 4][..]
                   ];

  let coefficients = polynomial[order];

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter()
                      .zip(&output[i..offset])
                      .fold(0, |result, (coefficient, signal)|
                            result + coefficient * signal);

    output[offset] = residual[i] + prediction;
  }
}

pub fn lpc_restore_signal(quantization_level: i8,
                          coefficients: &[i32],
                          residual: &[i32],
                          output: &mut [i32]) {
  let order = coefficients.len();

  debug_assert!(order <= MAX_LPC_ORDER);

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter().rev()
                       .zip(&output[i..offset])
                       .fold(0, |result, (coefficient, signal)|
                             result + coefficient * signal);

    output[offset] = residual[i] + (prediction >> quantization_level);
  }
}

pub fn decode(subframe: &Subframe, output: &mut [i32]) {
  match subframe.data {
    subframe::Data::Constant(constant)     => {
      for i in 0..output.len() {
        output[i] = constant
      }
    }
    subframe::Data::Verbatim(ref verbatim) => {
      let length = verbatim.len();

      unsafe {
        ptr::copy(verbatim.as_ptr(), output.as_mut_ptr(), length)
      }
    }
    subframe::Data::Fixed(ref fixed)       => {
      let order = fixed.order as usize;

      for i in 0..order {
        output[i] = fixed.warmup[i];
      }

      fixed_restore_signal(order, &fixed.residual, output);
    }
    subframe::Data::LPC(ref lpc)           => {
      let order        = lpc.order as usize;
      let coefficients = &lpc.qlp_coefficients[0..order];

      for i in 0..order {
        output[i] = lpc.warmup[i];
      }

      lpc_restore_signal(lpc.quantization_level, coefficients, &lpc.residual,
                         output);
    }
  }

  if subframe.wasted_bits > 0 {
    for value in output {
      *value <<= subframe.wasted_bits;
    }
  }
}

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

  #[test]
  fn test_fixed_restore_signal() {
    let residuals   = [ &[-19, -16, 17, -23, -7, 16, -16, -5, 3
                         , -8, -13, -15, -1][..]
                      , &[-6513][..]
                      ];
    let mut outputs = [ &mut [-729, -722, -667, 0, 0, 0, 0, 0, 0
                             , 0, 0, 0, 0, 0, 0, 0][..]
                      , &mut [21877, 27482, 0][..]
                      ];

    fixed_restore_signal(3, &residuals[0], &mut outputs[0]);
    fixed_restore_signal(2, &residuals[1], &mut outputs[1]);

    assert_eq!(&outputs[0], &[-729, -722, -667, -583, -486, -359, -225, -91
                             , 59, 209, 354, 497, 630, 740, 812, 845]);
    assert_eq!(&outputs[1], &[21877, 27482, 26574]);
  }
}
<commit_msg>Add tests for `lpc_restore_signal`<commit_after>use subframe;
use subframe::{Subframe, MAX_FIXED_ORDER, MAX_LPC_ORDER};

use std::ptr;

pub fn fixed_restore_signal(order: usize,
                            residual: &[i32],
                            output: &mut [i32]) {
  debug_assert!(order <= MAX_FIXED_ORDER);

  let polynomial = [ &[][..]
                   , &[1][..]
                   , &[-1, 2][..]
                   , &[1, -3, 3][..]
                   , &[-1, 4, -6, 4][..]
                   ];

  let coefficients = polynomial[order];

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter()
                      .zip(&output[i..offset])
                      .fold(0, |result, (coefficient, signal)|
                            result + coefficient * signal);

    output[offset] = residual[i] + prediction;
  }
}

pub fn lpc_restore_signal(quantization_level: i8,
                          coefficients: &[i32],
                          residual: &[i32],
                          output: &mut [i32]) {
  let order = coefficients.len();

  debug_assert!(order <= MAX_LPC_ORDER);

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter().rev()
                       .zip(&output[i..offset])
                       .fold(0, |result, (coefficient, signal)|
                             result + coefficient * signal);

    output[offset] = residual[i] + (prediction >> quantization_level);
  }
}

pub fn decode(subframe: &Subframe, output: &mut [i32]) {
  match subframe.data {
    subframe::Data::Constant(constant)     => {
      for i in 0..output.len() {
        output[i] = constant
      }
    }
    subframe::Data::Verbatim(ref verbatim) => {
      let length = verbatim.len();

      unsafe {
        ptr::copy(verbatim.as_ptr(), output.as_mut_ptr(), length)
      }
    }
    subframe::Data::Fixed(ref fixed)       => {
      let order = fixed.order as usize;

      for i in 0..order {
        output[i] = fixed.warmup[i];
      }

      fixed_restore_signal(order, &fixed.residual, output);
    }
    subframe::Data::LPC(ref lpc)           => {
      let order        = lpc.order as usize;
      let coefficients = &lpc.qlp_coefficients[0..order];

      for i in 0..order {
        output[i] = lpc.warmup[i];
      }

      lpc_restore_signal(lpc.quantization_level, coefficients, &lpc.residual,
                         output);
    }
  }

  if subframe.wasted_bits > 0 {
    for value in output {
      *value <<= subframe.wasted_bits;
    }
  }
}

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

  #[test]
  fn test_fixed_restore_signal() {
    let residuals   = [ &[-19, -16, 17, -23, -7, 16, -16, -5, 3
                         , -8, -13, -15, -1][..]
                      , &[-6513][..]
                      ];
    let mut outputs = [ &mut [-729, -722, -667, 0, 0, 0, 0, 0, 0
                             , 0, 0, 0, 0, 0, 0, 0][..]
                      , &mut [21877, 27482, 0][..]
                      ];

    fixed_restore_signal(3, &residuals[0], &mut outputs[0]);
    fixed_restore_signal(2, &residuals[1], &mut outputs[1]);

    assert_eq!(&outputs[0], &[-729, -722, -667, -583, -486, -359, -225, -91
                             , 59, 209, 354, 497, 630, 740, 812, 845]);
    assert_eq!(&outputs[1], &[21877, 27482, 26574]);
  }

  #[test]
  fn test_lpc_restore_signal() {
    let residuals    = [ &[-2, -23, 14, 6, 3, -4, 12, -2, 10][..]
                       , &[3157][..]
                       ];
    let coefficients = [ &[1042, -399, -75, -269, 121, 166, -75][..]
                       , &[1757, -1199, 879, -836, 555, -255, 119][..]
                       ];
    let mut outputs = [ &mut [-796, -547, -285, -32, 199, 443, 670
                             , 0, 0, 0, 0, 0, 0, 0, 0, 0][..]
                      , &mut [-21363, -21951, -22649, -24364, -27297, -26870
                             ,-30017, 0][..]
                      ];

    lpc_restore_signal(9, &coefficients[0], &residuals[0], &mut outputs[0]);
    lpc_restore_signal(10, &coefficients[1], &residuals[1], &mut outputs[1]);

    assert_eq!(&outputs[0], &[-796, -547, -285, -32, 199, 443, 670, 875
                             , 1046, 1208, 1343, 1454, 1541, 1616, 1663
                             , 1701]);
    assert_eq!(&outputs[1], &[-21363, -21951, -22649, -24364, -27297, -26870
                             , -30017, -29718]);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2020 Fabian Schuiki

//! Rvalue expressions
//!
//! An MIR representation for all expressions that may appear on the right-hand
//! side of an assignment.

use crate::{
    crate_prelude::*,
    mir::lvalue::Lvalue,
    ty::{Domain, Sign, Type},
    ParamEnv,
};
use std::collections::HashMap;

/// An rvalue expression.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Rvalue<'a> {
    /// A unique id.
    pub id: NodeId,
    /// The expression node which spawned this rvalue.
    pub origin: NodeId,
    /// The environment within which the rvalue lives.
    pub env: ParamEnv,
    /// The span in the source file where the rvalue originates from.
    pub span: Span,
    /// The type of the expression.
    pub ty: Type<'a>,
    /// The expression data.
    pub kind: RvalueKind<'a>,
}

impl<'a> Rvalue<'a> {
    /// Check whether the rvalue represents a lowering error tombstone.
    pub fn is_error(&self) -> bool {
        self.ty.is_error() || self.kind.is_error()
    }
}

/// The different forms an rvalue expression may take.
#[derive(Debug, Clone, Eq, PartialEq)]
#[allow(missing_docs)]
pub enum RvalueKind<'a> {
    /// A cast from a four-valued type to a two-valued type, or vice versa.
    /// E.g. `integer` to `int`, or `int` to `integer`.
    CastValueDomain {
        from: ty::Domain,
        to: ty::Domain,
        value: &'a Rvalue<'a>,
    },
    /// A cast from a single-element vector type to an atom type.
    /// E.g. `bit [0:0]` to `bit`.
    CastVectorToAtom {
        domain: ty::Domain,
        value: &'a Rvalue<'a>,
    },
    /// A cast from an atom type to a single-element vector type.
    /// E.g. `bit` to `bit [0:0]`.
    CastAtomToVector {
        domain: ty::Domain,
        value: &'a Rvalue<'a>,
    },
    /// A cast from one sign to another. E.g. `logic signed` to
    /// `logic unsigned`.
    CastSign(ty::Sign, &'a Rvalue<'a>),
    /// A cast from a simple bit type to a boolean.
    CastToBool(&'a Rvalue<'a>),
    /// Shrink the width of a vector type. E.g. `bit [31:0]` to `bit [7:0]`.
    Truncate(usize, &'a Rvalue<'a>),
    /// Increase the width of a vector by zero extension. E.g. `bit [7:0]` to
    /// `bit [31:0]`.
    ZeroExtend(usize, &'a Rvalue<'a>),
    /// Increase the width of a vector by sign extension. E.g. `bit signed
    /// [7:0]` to `bit signed [31:0]`.
    SignExtend(usize, &'a Rvalue<'a>),
    /// Constructor for an array.
    ConstructArray(HashMap<usize, &'a Rvalue<'a>>),
    /// Constructor for a struct.
    ConstructStruct(Vec<&'a Rvalue<'a>>),
    /// A constant value.
    Const(value::Value<'a>),
    /// A unary bitwise operator.
    UnaryBitwise {
        op: UnaryBitwiseOp,
        arg: &'a Rvalue<'a>,
    },
    /// A binary bitwise operator.
    BinaryBitwise {
        op: BinaryBitwiseOp,
        lhs: &'a Rvalue<'a>,
        rhs: &'a Rvalue<'a>,
    },
    /// An integral unary arithmetic operator.
    ///
    /// If any bit of the operand is x/z, the entire result is x.
    IntUnaryArith {
        op: IntUnaryArithOp,
        sign: Sign,
        domain: Domain,
        arg: &'a Rvalue<'a>,
    },
    /// An integral binary arithmetic operator.
    ///
    /// If any bit of the operands are x/z, the entire result is x.
    IntBinaryArith {
        op: IntBinaryArithOp,
        sign: Sign,
        domain: Domain,
        lhs: &'a Rvalue<'a>,
        rhs: &'a Rvalue<'a>,
    },
    /// An integral comparison operator.
    ///
    /// If any bit of the operands are x/z, the entire result is x.
    IntComp {
        op: IntCompOp,
        sign: Sign,
        domain: Domain,
        lhs: &'a Rvalue<'a>,
        rhs: &'a Rvalue<'a>,
    },
    /// Concatenate multiple values.
    ///
    /// The values are cast to and treated as packed bit vectors, and the result
    /// is yet another packed bit vector.
    Concat(Vec<&'a Rvalue<'a>>),
    /// Repeat a value multiple times.
    ///
    /// The value is cast to and treated as a packed bit vector, and the result
    /// is yet another packed bit vector.
    Repeat(usize, &'a Rvalue<'a>),
    /// A reference to a variable declaration.
    Var(NodeId),
    /// A reference to a port declaration.
    Port(NodeId),
    /// A bit- or part-select.
    Index {
        value: &'a Rvalue<'a>,
        base: &'a Rvalue<'a>,
        /// Length of the selection. Bit-select if zero.
        length: usize,
    },
    /// A struct field access.
    Member { value: &'a Rvalue<'a>, field: usize },
    /// The ternary operator.
    Ternary {
        cond: &'a Rvalue<'a>,
        true_value: &'a Rvalue<'a>,
        false_value: &'a Rvalue<'a>,
    },
    /// A shift operation.
    Shift {
        op: ShiftOp,
        arith: bool,
        value: &'a Rvalue<'a>,
        amount: &'a Rvalue<'a>,
    },
    /// A reduction operator.
    Reduction {
        op: BinaryBitwiseOp,
        arg: &'a Rvalue<'a>,
    },
    /// An assignment operator.
    Assignment {
        lvalue: &'a Lvalue<'a>,
        rvalue: &'a Rvalue<'a>,
        /// What value is produced as the assignment's value. This is usually
        /// the rvalue, but may be different (e.g. for the `i++` or `i--`).
        result: &'a Rvalue<'a>,
    },
    /// An error occurred during lowering.
    Error,
}

impl<'a> RvalueKind<'a> {
    /// Check whether the rvalue represents a lowering error tombstone.
    pub fn is_error(&self) -> bool {
        match self {
            RvalueKind::Error => true,
            _ => false,
        }
    }
}

/// The unary bitwise operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum UnaryBitwiseOp {
    Not,
}

/// The binary bitwise operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum BinaryBitwiseOp {
    And,
    Or,
    Xor,
}

/// The integer unary arithmetic operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum IntUnaryArithOp {
    Neg,
}

/// The integer binary arithmetic operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum IntBinaryArithOp {
    Add,
    Sub,
    Mul,
    Div,
    Mod,
    Pow,
}

/// The integer comparison operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum IntCompOp {
    Eq,
    Neq,
    Lt,
    Leq,
    Gt,
    Geq,
}

/// The shift operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum ShiftOp {
    Left,
    Right,
}
<commit_msg>svlog: mir: Deref Rvalue to RvalueKind<commit_after>// Copyright (c) 2016-2020 Fabian Schuiki

//! Rvalue expressions
//!
//! An MIR representation for all expressions that may appear on the right-hand
//! side of an assignment.

use crate::{
    crate_prelude::*,
    mir::lvalue::Lvalue,
    ty::{Domain, Sign, Type},
    ParamEnv,
};
use std::collections::HashMap;

/// An rvalue expression.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Rvalue<'a> {
    /// A unique id.
    pub id: NodeId,
    /// The expression node which spawned this rvalue.
    pub origin: NodeId,
    /// The environment within which the rvalue lives.
    pub env: ParamEnv,
    /// The span in the source file where the rvalue originates from.
    pub span: Span,
    /// The type of the expression.
    pub ty: Type<'a>,
    /// The expression data.
    pub kind: RvalueKind<'a>,
}

impl<'a> Rvalue<'a> {
    /// Check whether the rvalue represents a lowering error tombstone.
    pub fn is_error(&self) -> bool {
        self.ty.is_error() || self.kind.is_error()
    }
}

impl<'a> std::ops::Deref for Rvalue<'a> {
    type Target = RvalueKind<'a>;

    fn deref(&self) -> &RvalueKind<'a> {
        &self.kind
    }
}

/// The different forms an rvalue expression may take.
#[derive(Debug, Clone, Eq, PartialEq)]
#[allow(missing_docs)]
pub enum RvalueKind<'a> {
    /// A cast from a four-valued type to a two-valued type, or vice versa.
    /// E.g. `integer` to `int`, or `int` to `integer`.
    CastValueDomain {
        from: ty::Domain,
        to: ty::Domain,
        value: &'a Rvalue<'a>,
    },
    /// A cast from a single-element vector type to an atom type.
    /// E.g. `bit [0:0]` to `bit`.
    CastVectorToAtom {
        domain: ty::Domain,
        value: &'a Rvalue<'a>,
    },
    /// A cast from an atom type to a single-element vector type.
    /// E.g. `bit` to `bit [0:0]`.
    CastAtomToVector {
        domain: ty::Domain,
        value: &'a Rvalue<'a>,
    },
    /// A cast from one sign to another. E.g. `logic signed` to
    /// `logic unsigned`.
    CastSign(ty::Sign, &'a Rvalue<'a>),
    /// A cast from a simple bit type to a boolean.
    CastToBool(&'a Rvalue<'a>),
    /// Shrink the width of a vector type. E.g. `bit [31:0]` to `bit [7:0]`.
    Truncate(usize, &'a Rvalue<'a>),
    /// Increase the width of a vector by zero extension. E.g. `bit [7:0]` to
    /// `bit [31:0]`.
    ZeroExtend(usize, &'a Rvalue<'a>),
    /// Increase the width of a vector by sign extension. E.g. `bit signed
    /// [7:0]` to `bit signed [31:0]`.
    SignExtend(usize, &'a Rvalue<'a>),
    /// Constructor for an array.
    ConstructArray(HashMap<usize, &'a Rvalue<'a>>),
    /// Constructor for a struct.
    ConstructStruct(Vec<&'a Rvalue<'a>>),
    /// A constant value.
    Const(value::Value<'a>),
    /// A unary bitwise operator.
    UnaryBitwise {
        op: UnaryBitwiseOp,
        arg: &'a Rvalue<'a>,
    },
    /// A binary bitwise operator.
    BinaryBitwise {
        op: BinaryBitwiseOp,
        lhs: &'a Rvalue<'a>,
        rhs: &'a Rvalue<'a>,
    },
    /// An integral unary arithmetic operator.
    ///
    /// If any bit of the operand is x/z, the entire result is x.
    IntUnaryArith {
        op: IntUnaryArithOp,
        sign: Sign,
        domain: Domain,
        arg: &'a Rvalue<'a>,
    },
    /// An integral binary arithmetic operator.
    ///
    /// If any bit of the operands are x/z, the entire result is x.
    IntBinaryArith {
        op: IntBinaryArithOp,
        sign: Sign,
        domain: Domain,
        lhs: &'a Rvalue<'a>,
        rhs: &'a Rvalue<'a>,
    },
    /// An integral comparison operator.
    ///
    /// If any bit of the operands are x/z, the entire result is x.
    IntComp {
        op: IntCompOp,
        sign: Sign,
        domain: Domain,
        lhs: &'a Rvalue<'a>,
        rhs: &'a Rvalue<'a>,
    },
    /// Concatenate multiple values.
    ///
    /// The values are cast to and treated as packed bit vectors, and the result
    /// is yet another packed bit vector.
    Concat(Vec<&'a Rvalue<'a>>),
    /// Repeat a value multiple times.
    ///
    /// The value is cast to and treated as a packed bit vector, and the result
    /// is yet another packed bit vector.
    Repeat(usize, &'a Rvalue<'a>),
    /// A reference to a variable declaration.
    Var(NodeId),
    /// A reference to a port declaration.
    Port(NodeId),
    /// A bit- or part-select.
    Index {
        value: &'a Rvalue<'a>,
        base: &'a Rvalue<'a>,
        /// Length of the selection. Bit-select if zero.
        length: usize,
    },
    /// A struct field access.
    Member { value: &'a Rvalue<'a>, field: usize },
    /// The ternary operator.
    Ternary {
        cond: &'a Rvalue<'a>,
        true_value: &'a Rvalue<'a>,
        false_value: &'a Rvalue<'a>,
    },
    /// A shift operation.
    Shift {
        op: ShiftOp,
        arith: bool,
        value: &'a Rvalue<'a>,
        amount: &'a Rvalue<'a>,
    },
    /// A reduction operator.
    Reduction {
        op: BinaryBitwiseOp,
        arg: &'a Rvalue<'a>,
    },
    /// An assignment operator.
    Assignment {
        lvalue: &'a Lvalue<'a>,
        rvalue: &'a Rvalue<'a>,
        /// What value is produced as the assignment's value. This is usually
        /// the rvalue, but may be different (e.g. for the `i++` or `i--`).
        result: &'a Rvalue<'a>,
    },
    /// An error occurred during lowering.
    Error,
}

impl<'a> RvalueKind<'a> {
    /// Check whether the rvalue represents a lowering error tombstone.
    pub fn is_error(&self) -> bool {
        match self {
            RvalueKind::Error => true,
            _ => false,
        }
    }
}

/// The unary bitwise operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum UnaryBitwiseOp {
    Not,
}

/// The binary bitwise operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum BinaryBitwiseOp {
    And,
    Or,
    Xor,
}

/// The integer unary arithmetic operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum IntUnaryArithOp {
    Neg,
}

/// The integer binary arithmetic operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum IntBinaryArithOp {
    Add,
    Sub,
    Mul,
    Div,
    Mod,
    Pow,
}

/// The integer comparison operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum IntCompOp {
    Eq,
    Neq,
    Lt,
    Leq,
    Gt,
    Geq,
}

/// The shift operators.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum ShiftOp {
    Left,
    Right,
}
<|endoftext|>


<commit_before>/// Figure 8.8: Avoid zombie processes by calling fork twice
///
/// $ f08-avoid-zombie
/// $ f08-avoid-zombie && sleep 0.1
/// second child, parent pid = 1

extern crate libc;
extern crate apue;

use libc::{fork, usleep, waitpid, getppid, exit};
use apue::{LibcResult, err_sys};

// separate function to avoid one indent because of the unsafe block
unsafe fn doit() {
    let pid = fork().to_option().expect("fork error");
    match pid {
        0 => {
            let pid = fork().to_option().expect("fork error");
            if pid > 0 {
                // parent from second fork == first child
                exit(0);
            }
            // we're the second child; our parent becomes init
            // as soon as our real parent calls exit() (3 lines above)
            // After 2 seconds sleep our parent will be dead and
            // init will reap our status.
            usleep(10);
            println!("second child, parent pid = {}", getppid());
            exit(0);
        }
        _ => {
            // wait for first child
            if waitpid(pid, std::ptr::null_mut(), 0) != pid {
                err_sys("waitpid error");
            }
        }
    }
}

fn main() {
    unsafe { doit() };
}
<commit_msg>fix f08-avoid-zombie for linux<commit_after>/// Figure 8.8: Avoid zombie processes by calling fork twice
///
/// $ f08-avoid-zombie
/// $ f08-avoid-zombie && sleep 0.1
/// second child, parent pid = 1

extern crate libc;
extern crate apue;

use libc::{fork, usleep, waitpid, getppid, exit};
use apue::{LibcResult, err_sys};

// separate function to avoid one indent because of the unsafe block
unsafe fn doit() {
    let pid = fork().to_option().expect("fork error");
    match pid {
        0 => {
            let pid = fork().to_option().expect("fork error");
            if pid > 0 {
                // parent from second fork == first child
                exit(0);
            }
            // we're the second child; our parent becomes init
            // as soon as our real parent calls exit() (3 lines above)
            // After 2 seconds sleep our parent will be dead and
            // init will reap our status.
            usleep(1000);
            println!("second child, parent pid = {}", getppid());
            exit(0);
        }
        _ => {
            // wait for first child
            if waitpid(pid, std::ptr::null_mut(), 0) != pid {
                err_sys("waitpid error");
            }
        }
    }
}

fn main() {
    unsafe { doit() };
}
<|endoftext|>


<commit_before>use crate::constants::EMBED_COLOR;
use crate::discord::slash_commands::weather::WeatherCommandOptionFailure::MissingOption;
use crate::discord::slash_commands::SlashCommand;
use crate::discord::util::{
    invisible_failure_reply, verify_guild_slash_command, ApplicationCommandInteractionDataExt,
};
use crate::util::now;
use crate::Config;
use anyhow::bail;
use async_trait::async_trait;
use chrono::NaiveDateTime;
use reqwest::{Client, ClientBuilder};
use serde::Deserialize;
use serenity::builder::CreateApplicationCommand;
use serenity::client::Context;
use serenity::model::interactions::application_command::{
    ApplicationCommandInteraction, ApplicationCommandInteractionData, ApplicationCommandOptionType,
};
use serenity::model::interactions::InteractionResponseType;
use typemap_rev::TypeMap;

const GEOCODE_URL: &str = "https://maps.googleapis.com/maps/api/geocode/json";
const DARKSKY_URL: &str = "https://api.darksky.net/forecast";

#[derive(Deserialize)]
struct GeocodeResponse {
    status: String,
    results: Vec<GeocodeResponseResult>,
}

#[derive(Deserialize)]
struct GeocodeResponseResult {
    formatted_address: String,
    geometry: GeocodeResponseGeometry,
}

#[derive(Deserialize)]
struct GeocodeResponseGeometry {
    location: GeocodeResponseLocation,
}

#[derive(Deserialize)]
struct GeocodeResponseLocation {
    lat: f32,
    lng: f32,
}

#[derive(Deserialize)]
pub struct DarkskyResponse {
    offset: i32,
    currently: DarkskyResponseCurrently,
}

#[derive(Deserialize)]
pub struct DarkskyResponseCurrently {
    summary: String,
    temperature: f32,
    humidity: f32,
    icon: String,
}

pub struct WeatherCommand {
    client: Client,
}

impl WeatherCommand {
    pub fn new() -> WeatherCommand {
        WeatherCommand {
            client: ClientBuilder::new()
                .user_agent("Safety Jim")
                .build()
                .expect("constructing client failed"),
        }
    }
}

struct WeatherCommandOptions<'a> {
    address: &'a str,
}

enum WeatherCommandOptionFailure {
    MissingOption,
}

fn generate_options(
    data: &ApplicationCommandInteractionData,
) -> Result<WeatherCommandOptions, WeatherCommandOptionFailure> {
    let address = if let Some(s) = data.string("address") {
        s
    } else {
        return Err(MissingOption);
    };

    Ok(WeatherCommandOptions { address })
}

#[async_trait]
impl SlashCommand for WeatherCommand {
    fn command_name(&self) -> &'static str {
        "weather"
    }

    fn create_command<'a>(
        &self,
        command: &'a mut CreateApplicationCommand,
    ) -> &'a mut CreateApplicationCommand {
        command
            .name("weather")
            .description("gives current weather information for given address")
            .default_permission(true)
            .create_option(|option| {
                option
                    .name("address")
                    .description("address for weather location")
                    .kind(ApplicationCommandOptionType::String)
                    .required(true)
            })
    }

    async fn handle_command(
        &self,
        context: &Context,
        interaction: &ApplicationCommandInteraction,
        config: &Config,
        _services: &TypeMap,
    ) -> anyhow::Result<()> {
        let _ = verify_guild_slash_command(interaction)?;

        let options = match generate_options(&interaction.data) {
            Ok(options) => options,
            Err(MissingOption) => {
                bail!("interaction has missing data options")
            }
        };

        let geocode_response = match self
            .client
            .get(GEOCODE_URL)
            .query(&[
                ("key", config.geocode_token.as_str()),
                ("address", options.address),
            ])
            .send()
            .await?
            .json::<GeocodeResponse>()
            .await
        {
            Ok(response) => response,
            Err(err) => {
                println!("{}", err);
                invisible_failure_reply(&*context.http, interaction, "Failed to get address data!")
                    .await;
                return Ok(());
            }
        };

        if geocode_response.status != "OK" {
            invisible_failure_reply(
                &*context.http,
                interaction,
                "Could not detect given address!",
            )
            .await;
            return Ok(());
        }

        let geocode_result = if let Some(result) = geocode_response.results.first() {
            result
        } else {
            invisible_failure_reply(&*context.http, interaction, "Failed to get address data!")
                .await;
            return Ok(());
        };

        let formatted_address = &geocode_result.formatted_address;
        let lat = geocode_result.geometry.location.lat;
        let lng = geocode_result.geometry.location.lng;

        let darksky_response = match self
            .client
            .get(format!(
                "{}/{}/{},{}",
                DARKSKY_URL, config.darksky_token, lat, lng
            ))
            .send()
            .await?
            .json::<DarkskyResponse>()
            .await
        {
            Ok(response) => response,
            Err(_) => {
                invisible_failure_reply(&*context.http, interaction, "Failed to get weather data!")
                    .await;
                return Ok(());
            }
        };

        let local_time_offset = darksky_response.offset;
        let local_timestamp = now() as i64 + (local_time_offset * 60 * 60) as i64;
        let local_date = NaiveDateTime::from_timestamp(local_timestamp, 0);
        let local_date_formatted = local_date.format("%a, %d %b %Y %H:%M:%S GMT ");
        let local_date_str = if local_time_offset > 0 {
            format!("{} +{}", local_date_formatted, local_time_offset)
        } else {
            format!("{} {}", local_date_formatted, local_time_offset)
        };

        let summary = darksky_response.currently.summary;
        let temp_f = darksky_response.currently.temperature;
        let temp_c = ((temp_f - 32.) * 5.) / 9.;
        let humidity = (darksky_response.currently.humidity * 100.) as i32;
        let icon = darksky_response.currently.icon;

        let description = match icon.as_str() {
            "clear-day" => ":sunny:",
            "clear-night" => ":crescent_moon:",
            "rain" => ":cloud_rain:",
            "snow" => ":cloud_snow:",
            "sleet" => ":cloud_snow:",
            "partly-cloudy-day" => ":partly_sunny:",
            "partly-cloudy-night" => ":partly_sunny:",
            "fog" => ":fog:",
            "cloudy" => ":cloud:",
            "wind" => ":wind_blowing_face:",
            _ => "<unknown>",
        };

        let _ = interaction
            .create_interaction_response(&*context.http, |response| {
                response
                    .kind(InteractionResponseType::ChannelMessageWithSource)
                    .interaction_response_data(|message| {
                        message.create_embed(|embed| {
                            embed
                                .colour(EMBED_COLOR)
                                .title(format!("Weather in {}", formatted_address))
                                .footer(|footer| {
                                    footer.text(format!("Local Time: {}", local_date_str))
                                })
                                .field("Summary", summary, false)
                                .field(
                                    "Temperature",
                                    format!("{} °C / {} °F", temp_c as i32, temp_f as i32),
                                    true,
                                )
                                .field("Humidity", format!("{}%", humidity), true)
                                .description(description)
                        })
                    })
            })
            .await;

        Ok(())
    }
}
<commit_msg>Remove extra println<commit_after>use crate::constants::EMBED_COLOR;
use crate::discord::slash_commands::weather::WeatherCommandOptionFailure::MissingOption;
use crate::discord::slash_commands::SlashCommand;
use crate::discord::util::{
    invisible_failure_reply, verify_guild_slash_command, ApplicationCommandInteractionDataExt,
};
use crate::util::now;
use crate::Config;
use anyhow::bail;
use async_trait::async_trait;
use chrono::NaiveDateTime;
use reqwest::{Client, ClientBuilder};
use serde::Deserialize;
use serenity::builder::CreateApplicationCommand;
use serenity::client::Context;
use serenity::model::interactions::application_command::{
    ApplicationCommandInteraction, ApplicationCommandInteractionData, ApplicationCommandOptionType,
};
use serenity::model::interactions::InteractionResponseType;
use typemap_rev::TypeMap;

const GEOCODE_URL: &str = "https://maps.googleapis.com/maps/api/geocode/json";
const DARKSKY_URL: &str = "https://api.darksky.net/forecast";

#[derive(Deserialize)]
struct GeocodeResponse {
    status: String,
    results: Vec<GeocodeResponseResult>,
}

#[derive(Deserialize)]
struct GeocodeResponseResult {
    formatted_address: String,
    geometry: GeocodeResponseGeometry,
}

#[derive(Deserialize)]
struct GeocodeResponseGeometry {
    location: GeocodeResponseLocation,
}

#[derive(Deserialize)]
struct GeocodeResponseLocation {
    lat: f32,
    lng: f32,
}

#[derive(Deserialize)]
pub struct DarkskyResponse {
    offset: i32,
    currently: DarkskyResponseCurrently,
}

#[derive(Deserialize)]
pub struct DarkskyResponseCurrently {
    summary: String,
    temperature: f32,
    humidity: f32,
    icon: String,
}

pub struct WeatherCommand {
    client: Client,
}

impl WeatherCommand {
    pub fn new() -> WeatherCommand {
        WeatherCommand {
            client: ClientBuilder::new()
                .user_agent("Safety Jim")
                .build()
                .expect("constructing client failed"),
        }
    }
}

struct WeatherCommandOptions<'a> {
    address: &'a str,
}

enum WeatherCommandOptionFailure {
    MissingOption,
}

fn generate_options(
    data: &ApplicationCommandInteractionData,
) -> Result<WeatherCommandOptions, WeatherCommandOptionFailure> {
    let address = if let Some(s) = data.string("address") {
        s
    } else {
        return Err(MissingOption);
    };

    Ok(WeatherCommandOptions { address })
}

#[async_trait]
impl SlashCommand for WeatherCommand {
    fn command_name(&self) -> &'static str {
        "weather"
    }

    fn create_command<'a>(
        &self,
        command: &'a mut CreateApplicationCommand,
    ) -> &'a mut CreateApplicationCommand {
        command
            .name("weather")
            .description("gives current weather information for given address")
            .default_permission(true)
            .create_option(|option| {
                option
                    .name("address")
                    .description("address for weather location")
                    .kind(ApplicationCommandOptionType::String)
                    .required(true)
            })
    }

    async fn handle_command(
        &self,
        context: &Context,
        interaction: &ApplicationCommandInteraction,
        config: &Config,
        _services: &TypeMap,
    ) -> anyhow::Result<()> {
        let _ = verify_guild_slash_command(interaction)?;

        let options = match generate_options(&interaction.data) {
            Ok(options) => options,
            Err(MissingOption) => {
                bail!("interaction has missing data options")
            }
        };

        let geocode_response = match self
            .client
            .get(GEOCODE_URL)
            .query(&[
                ("key", config.geocode_token.as_str()),
                ("address", options.address),
            ])
            .send()
            .await?
            .json::<GeocodeResponse>()
            .await
        {
            Ok(response) => response,
            Err(err) => {
                invisible_failure_reply(&*context.http, interaction, "Failed to get address data!")
                    .await;
                return Ok(());
            }
        };

        if geocode_response.status != "OK" {
            invisible_failure_reply(
                &*context.http,
                interaction,
                "Could not detect given address!",
            )
            .await;
            return Ok(());
        }

        let geocode_result = if let Some(result) = geocode_response.results.first() {
            result
        } else {
            invisible_failure_reply(&*context.http, interaction, "Failed to get address data!")
                .await;
            return Ok(());
        };

        let formatted_address = &geocode_result.formatted_address;
        let lat = geocode_result.geometry.location.lat;
        let lng = geocode_result.geometry.location.lng;

        let darksky_response = match self
            .client
            .get(format!(
                "{}/{}/{},{}",
                DARKSKY_URL, config.darksky_token, lat, lng
            ))
            .send()
            .await?
            .json::<DarkskyResponse>()
            .await
        {
            Ok(response) => response,
            Err(_) => {
                invisible_failure_reply(&*context.http, interaction, "Failed to get weather data!")
                    .await;
                return Ok(());
            }
        };

        let local_time_offset = darksky_response.offset;
        let local_timestamp = now() as i64 + (local_time_offset * 60 * 60) as i64;
        let local_date = NaiveDateTime::from_timestamp(local_timestamp, 0);
        let local_date_formatted = local_date.format("%a, %d %b %Y %H:%M:%S GMT ");
        let local_date_str = if local_time_offset > 0 {
            format!("{} +{}", local_date_formatted, local_time_offset)
        } else {
            format!("{} {}", local_date_formatted, local_time_offset)
        };

        let summary = darksky_response.currently.summary;
        let temp_f = darksky_response.currently.temperature;
        let temp_c = ((temp_f - 32.) * 5.) / 9.;
        let humidity = (darksky_response.currently.humidity * 100.) as i32;
        let icon = darksky_response.currently.icon;

        let description = match icon.as_str() {
            "clear-day" => ":sunny:",
            "clear-night" => ":crescent_moon:",
            "rain" => ":cloud_rain:",
            "snow" => ":cloud_snow:",
            "sleet" => ":cloud_snow:",
            "partly-cloudy-day" => ":partly_sunny:",
            "partly-cloudy-night" => ":partly_sunny:",
            "fog" => ":fog:",
            "cloudy" => ":cloud:",
            "wind" => ":wind_blowing_face:",
            _ => "<unknown>",
        };

        let _ = interaction
            .create_interaction_response(&*context.http, |response| {
                response
                    .kind(InteractionResponseType::ChannelMessageWithSource)
                    .interaction_response_data(|message| {
                        message.create_embed(|embed| {
                            embed
                                .colour(EMBED_COLOR)
                                .title(format!("Weather in {}", formatted_address))
                                .footer(|footer| {
                                    footer.text(format!("Local Time: {}", local_date_str))
                                })
                                .field("Summary", summary, false)
                                .field(
                                    "Temperature",
                                    format!("{} °C / {} °F", temp_c as i32, temp_f as i32),
                                    true,
                                )
                                .field("Humidity", format!("{}%", humidity), true)
                                .description(description)
                        })
                    })
            })
            .await;

        Ok(())
    }
}
<|endoftext|>


<commit_before>use libc::c_long;

// a raw Core Foundation reference. It may or may not have been
// CFRetain'ed, depending on whether it was obtained via ownership or
// borrow semantics.
trait AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef;
}

pub type Boolean = u8;

pub type CFIndex = c_long;
pub type CFOptionFlags = u32;
pub struct CFRange {
    location: CFIndex,
    length: CFIndex
}

fn CFRangeMake(off: CFIndex, len: CFIndex) -> CFRange {
    CFRange { location: off, length: len }
}

struct __CFAllocator { private: () }
pub type CFAllocatorRef = *__CFAllocator;

struct __CFNull { private: () }
pub type CFNullRef = *__CFNull;

pub type CFHashCode = libc::c_ulong;
pub type CFTypeID = libc::c_ulong;

struct __CFType { private: () }
pub type CFTypeRef = *__CFType;

pub impl CFTypeRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self }
}

struct CFWrapper<T:Copy AbstractCFTypeRef, PlaceholderType1, PlaceholderType2> {
    obj: T,

    drop {
        unsafe {
            assert CFGetRetainCount(cast::transmute(self.obj)) > 0 as CFIndex;
            // sadly, cannot use obj.as_type_ref() here, because drop
            // cannot make virtual method calls using trait
            // types. Instead, just transmute the bugger.
            CFRelease(cast::transmute(self.obj))
        }
    }
}

pub type CFType = CFWrapper<CFTypeRef, (), ()>;

pub impl<T:Copy AbstractCFTypeRef, E1, E2>
    CFWrapper<T, E1, E2> {
    pure fn borrow_ref(&self) -> &self/T {
        &self.obj
    }

    pure fn borrow_type_ref() -> &self/CFTypeRef unsafe {
        cast::transmute(&self.obj)
    }

    // Use this when following Core Foundation's "Create" rule; i.e., the wrapper assumes ownership.
    // The object has already been retained, so we need not increment the retain count ourself.
    static pure fn wrap_owned(some_ref: T) -> CFWrapper<T,E1,E2> {
        unsafe { assert CFGetRetainCount(some_ref.as_type_ref()) == 1 as CFIndex; }
        CFWrapper { obj: some_ref }
    }

    // Use this when following Core Foundation's "Get" rule. The wrapper does not have ownership.
    // Twe need to increment object's the retain count so it isn't freed out from under our noses.
    static pure fn wrap_shared(some_ref: T) -> CFWrapper<T,E1,E2> {
        unsafe { CFRetain(some_ref.as_type_ref()); }
        CFWrapper { obj: some_ref }
    }

    // Unwraps the wrapper, returning the underlying AbstractCFType.
    static fn unwrap(wrapper: CFWrapper<T,E1,E2>) -> T {
        wrapper.obj
    }

    static fn to_CFType(wrapper: CFWrapper<T,E1,E2>) -> CFType unsafe {
        cast::transmute(move wrapper)
    }

    static fn from_CFType(wrapper: CFType) -> CFWrapper<T,E1,E2> unsafe {
        cast::transmute(move wrapper)
    }

    static fn clone(wrapper: &CFWrapper<T,E1,E2>) -> CFWrapper<T,E1,E2> {
        CFWrapper::wrap_shared(*wrapper.borrow_ref())
    }

    pure fn retain_count() -> CFIndex unsafe {
        CFGetRetainCount(*self.borrow_type_ref())
    }

    pure fn type_id() -> CFTypeID unsafe {
        CFGetTypeID(*self.borrow_type_ref())
    }

    pure fn show() unsafe {
        CFShow(*self.borrow_type_ref());
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFBase.h
     */

    /* CFAllocator Reference */
    // N.B. Many CFAllocator functions and constants are omitted here.
    const kCFAllocatorDefault: CFAllocatorRef;
    const kCFAllocatorSystemDefault: CFAllocatorRef;
    const kCFAllocatorMalloc: CFAllocatorRef;
    const kCFAllocatorMallocZone: CFAllocatorRef;
    const kCFAllocatorNull: CFAllocatorRef;
    const kCFAllocatorUseContext: CFAllocatorRef;

    /* CFNull Reference */

    const kCFNull: CFNullRef;

    /* CFType Reference */

    //fn CFCopyDescription
    //fn CFCopyTypeIDDescription
    //fn CFEqual
    //fn CFGetAllocator
    fn CFGetRetainCount(cf: CFTypeRef) -> CFIndex;
    fn CFGetTypeID(cf: CFTypeRef) -> CFTypeID;
    fn CFHash(cf: CFTypeRef) -> CFHashCode;
    //fn CFMakeCollectable
    fn CFRelease(cf: CFTypeRef);
    fn CFRetain(cf: CFTypeRef) -> CFTypeRef;
    fn CFShow(obj: CFTypeRef);

    /* Base Utilities Reference */
    // N.B. Some things missing here.
}
<commit_msg>Remove erroneous assertion about retain count; add note.<commit_after>use libc::c_long;

// a raw Core Foundation reference. It may or may not have been
// CFRetain'ed, depending on whether it was obtained via ownership or
// borrow semantics.
trait AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef;
}

pub type Boolean = u8;

pub type CFIndex = c_long;
pub type CFOptionFlags = u32;
pub struct CFRange {
    location: CFIndex,
    length: CFIndex
}

fn CFRangeMake(off: CFIndex, len: CFIndex) -> CFRange {
    CFRange { location: off, length: len }
}

struct __CFAllocator { private: () }
pub type CFAllocatorRef = *__CFAllocator;

struct __CFNull { private: () }
pub type CFNullRef = *__CFNull;

pub type CFHashCode = libc::c_ulong;
pub type CFTypeID = libc::c_ulong;

struct __CFType { private: () }
pub type CFTypeRef = *__CFType;

pub impl CFTypeRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self }
}

struct CFWrapper<T:Copy AbstractCFTypeRef, PlaceholderType1, PlaceholderType2> {
    obj: T,

    drop {
        unsafe {
            assert CFGetRetainCount(cast::transmute(self.obj)) > 0 as CFIndex;
            // sadly, cannot use obj.as_type_ref() here, because drop
            // cannot make virtual method calls using trait
            // types. Instead, just transmute the bugger.
            CFRelease(cast::transmute(self.obj))
        }
    }
}

pub type CFType = CFWrapper<CFTypeRef, (), ()>;

pub impl<T:Copy AbstractCFTypeRef, E1, E2>
    CFWrapper<T, E1, E2> {
    pure fn borrow_ref(&self) -> &self/T {
        &self.obj
    }

    pure fn borrow_type_ref() -> &self/CFTypeRef unsafe {
        cast::transmute(&self.obj)
    }

    // Use this when following Core Foundation's "Create" rule; i.e., the wrapper assumes ownership.
    // The object has already been retained, so we need not increment the retain count ourself.
    static pure fn wrap_owned(some_ref: T) -> CFWrapper<T,E1,E2> {
        // N.B. we can't make any assertions about retain count here,
        // because returned things are only guaranteed to be already
        // retained. Strings, for example, could be interned.
        CFWrapper { obj: some_ref }
    }

    // Use this when following Core Foundation's "Get" rule. The wrapper does not have ownership.
    // Twe need to increment object's the retain count so it isn't freed out from under our noses.
    static pure fn wrap_shared(some_ref: T) -> CFWrapper<T,E1,E2> {
        unsafe { CFRetain(some_ref.as_type_ref()); }
        CFWrapper { obj: some_ref }
    }

    // Unwraps the wrapper, returning the underlying AbstractCFType.
    static fn unwrap(wrapper: CFWrapper<T,E1,E2>) -> T {
        wrapper.obj
    }

    static fn to_CFType(wrapper: CFWrapper<T,E1,E2>) -> CFType unsafe {
        cast::transmute(move wrapper)
    }

    static fn from_CFType(wrapper: CFType) -> CFWrapper<T,E1,E2> unsafe {
        cast::transmute(move wrapper)
    }

    static fn clone(wrapper: &CFWrapper<T,E1,E2>) -> CFWrapper<T,E1,E2> {
        CFWrapper::wrap_shared(*wrapper.borrow_ref())
    }

    pure fn retain_count() -> CFIndex unsafe {
        CFGetRetainCount(*self.borrow_type_ref())
    }

    pure fn type_id() -> CFTypeID unsafe {
        CFGetTypeID(*self.borrow_type_ref())
    }

    pure fn show() unsafe {
        CFShow(*self.borrow_type_ref());
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFBase.h
     */

    /* CFAllocator Reference */
    // N.B. Many CFAllocator functions and constants are omitted here.
    const kCFAllocatorDefault: CFAllocatorRef;
    const kCFAllocatorSystemDefault: CFAllocatorRef;
    const kCFAllocatorMalloc: CFAllocatorRef;
    const kCFAllocatorMallocZone: CFAllocatorRef;
    const kCFAllocatorNull: CFAllocatorRef;
    const kCFAllocatorUseContext: CFAllocatorRef;

    /* CFNull Reference */

    const kCFNull: CFNullRef;

    /* CFType Reference */

    //fn CFCopyDescription
    //fn CFCopyTypeIDDescription
    //fn CFEqual
    //fn CFGetAllocator
    fn CFGetRetainCount(cf: CFTypeRef) -> CFIndex;
    fn CFGetTypeID(cf: CFTypeRef) -> CFTypeID;
    fn CFHash(cf: CFTypeRef) -> CFHashCode;
    //fn CFMakeCollectable
    fn CFRelease(cf: CFTypeRef);
    fn CFRetain(cf: CFTypeRef) -> CFTypeRef;
    fn CFShow(obj: CFTypeRef);

    /* Base Utilities Reference */
    // N.B. Some things missing here.
}
<|endoftext|>


<commit_before>//
// gash.rs
// by Nathan Typanski
//
// 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;

use std::{run, os};
use std::io::buffered::BufferedReader;
use std::io::{stdin, stdio, File, Truncate, Write};
use std::io::process::ProcessExit;
use std::io::signal::{Listener, Interrupt};
use std::path::posix::Path;
use std::option::Option;
use std::task::try;
use std::run::Process;
use std::run::ProcessOptions;
use std::comm::Port;

use extra::getopts;

use std::libc::types::os::arch::posix88::pid_t;
use std::libc;

extern {
  pub fn kill(pid: libc::pid_t, sig: libc::c_int) -> libc::c_int;
}

// The basic unit for a command that could be run.
struct Cmd {
    program : ~str,
    argv : ~[~str],
}

impl Cmd {
    fn new(cmd_name: &str) -> Option<Cmd> {
        let mut argv: ~[~str] = split_words(cmd_name);
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            let argv : ~[~str] = argv;
            Some(Cmd {
                program : program,
                argv : argv,
            })
        }
        else {
            None
        }
    }
}

struct FgProcess {
    command     : ~str,
    args        : ~[~str],
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl FgProcess {
    fn new(cmd : Cmd,
           stdin : Option<i32>,
           stdout : Option<i32>)
        -> Option<FgProcess>
    {
        if (cmd_exists(&cmd)) {
            Some(FgProcess {
                command     : cmd.program.to_owned(),
                args        : cmd.argv.to_owned(),
                stdin       : stdin,
                stdout      : stdout,
            })
        }
        else { None }
    }

    fn run(&mut self) -> Option<Process> {
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        let options = ProcessOptions {
            env    : None,
            dir    : None,
            in_fd  : self.stdin,
            out_fd : self.stdout,
            err_fd : None,
        };
        Process::new(command, args, options)
    }
}

// Background processes are handled differently, but not *that* differently:
// we need to keep track of an ProcessExit port for determining whether a
// process has finished running, as well as a pid for the process (for killing
// it when the shell terminates).
struct BgProcess {
    command      : ~str,
    args         : ~[~str],
    exit_port    : Option<Port<ProcessExit>>,
    pid          : Option<i32>,
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl BgProcess {
    fn new(cmd : Cmd) -> Option<BgProcess> {
        if (cmd_exists(&cmd)) {
            Some(BgProcess {
                command: cmd.program.to_owned(),
                args: cmd.argv.to_owned(),
                exit_port: None,
                pid: None,
                stdin: None,
                stdout: None,
            })
        }
        else { None }
    }

    fn run(&mut self) -> Option<pid_t> {
        // Process exit ports; used for checking dead status.
        let (port, chan): (Port<ProcessExit>, Chan<ProcessExit>) = Chan::new();
        // Process ports; these don't leave this function and are used for
        // sending the PID out in the return value.
        let (pidport, pidchan): (Port<Option<pid_t>>, Chan<Option<pid_t>>)
                            = Chan::new();
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        spawn(proc() {
            let options = ProcessOptions {
                env    : None,
                dir    : None,
                in_fd  : None,
                out_fd : None,
                err_fd : None,
            };
            let maybe_process = Process::new(command, args, options);
            match maybe_process {
                Some(mut process) => {
                    // Send the pid out for the return value
                    pidchan.try_send_deferred(Some(process.get_id()));
                    chan.try_send_deferred(process.finish());
                }
                None => {
                    pidchan.try_send_deferred(None);
                }
            }
        });
        self.exit_port = Some(port);
        self.pid = pidport.recv();
        self.pid
    }
}

struct Shell {
    cmd_prompt : ~str,
    history    : ~[~str],
    processes  : ~[~BgProcess],
    broken : bool,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
            processes: ~[],
            broken: false,
        }
    }

    fn run(&mut self) {
        // Setup the interrupt handler. Has to happen here, or it won't
        // retain control over interrupts.
        let mut listener = Listener::new();
        listener.register(Interrupt);
        let port = listener.port;
        spawn(proc() {
            try(proc() {
                loop {
                    match port.recv_opt() {
                        Some(Interrupt) => {
                        }
                        None => {
                            break;
                        }
                        _ => {
                        }
                    }
                }
                return 0
            });
            return ();
        });

        self.display_prompt();
    }

    fn display_prompt(&mut self) {
        // Standard input reader
        let mut stdin = BufferedReader::new(stdin());
        // Show the prompt
        print(self.cmd_prompt);
        stdio::flush();

        let line = stdin.read_line().unwrap();
        let cmd_line = line.trim().to_owned();
        let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
        self.disown_dead();

        // Push commands onto the history
        match program {
            "" => {}
            _  => {
                self.push_hist(cmd_line)
            }
        }

        match program {
            "" =>  {
                self.display_prompt();
            }
            "exit" =>  {
                self.kill_all();
            }
            "history" => {
                self.show_hist();
                self.display_prompt();
            }
            "jobs" => {
                self.jobs();
                self.display_prompt();
            }
            "cd" =>  {
                self.chdir(cmd_line);
                self.display_prompt();
            }
            _ => {
                self.run_cmdline(cmd_line);
                self.display_prompt();
            }
        }
    }

    // Nice extra feature: list running jobs.
    fn jobs(&mut self) {
        for cmd in self.processes.iter() {
            print!("{:s}", cmd.command);
            match cmd.pid {
                Some(pid) => {
                    println!(" {:i}", pid);
                }
                None => {
                    println("");
                }
            }
        }
    }

    // Remove dead processes from the list of processes.
    fn disown_dead(&mut self) {
        let mut dead : ~[uint];
        dead = ~[];
        let mut i = 0;
        for cmd in self.processes.iter() {
            borrowed_maybe(&cmd.exit_port, |port| match port.try_recv() {
                Some(_) => {dead.push(i); Some(i)},
                _ => None,
            });
            i += 1;
        }
        for &p in dead.iter() {
            self.processes.remove(p);
        }
    }

    fn kill_all(&mut self) {
        for p in self.processes.iter() {
            match p.pid {
                Some(pid) => {
                    unsafe {
                        // Kill perhaps isn't the best way to do this, but
                        // without it we have no way of killing our background
                        // processes with only the PID - we'd need the process
                        // object itself, and that can't be moved out of the
                        // spawn() that it's trapped inside.
                        kill(pid, 15);
                    }
                }
                None => {
                }
            }
        }
    }

    // Push a new command onto history.
    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] = split_words(cmd_line);
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    // Determine the type of the current block, and send it to the right
    // parsing function.
    fn run_cmdline(&mut self, cmd_line: &str) {
        if cmd_line.contains_char('>') {
            parse_r_redirect(cmd_line);
        }
        else if cmd_line.contains_char('<') {
            parse_l_redirect(cmd_line);
        }
        else if cmd_line.contains_char('|') {
            self.parse_pipeline(cmd_line);
        }
        else {
            self.parse_process(cmd_line);
        }
    }

    // Parse a new lone process. Background/foreground it appropriately.
    fn parse_process(&mut self, cmd_line : &str) -> Option<Process>{
        maybe(Cmd::new(cmd_line), |cmd| {
            if (cmd.argv.len() > 0 && cmd.argv.last() == &~"&") {
                let mut argv = cmd.argv.to_owned();
                argv.pop();
                self.make_bg_process(Cmd{
                    program:cmd.program,
                    argv:argv});
                None
            }
            else {
                make_process(cmd, Some(0), Some(1))
            }
        })
    }

    // Parse a process pipeline, and redirect stdin/stdout appropriately.
    fn parse_pipeline(&mut self, cmd_line : &str) -> Option<~run::Process> {
        let pair : ~[&str] = cmd_line.rsplitn('|', 1).collect();
        maybe(Cmd::new(pair[0].trim()), |cmd| {
            if pair.len() > 1 {
                let two = self.parse_pipeline(pair[1].trim());
                self.pipe_input(cmd, two)
            }
            else {
                maybe(make_process(cmd, None, None), |process| Some(~process))
            }
        })
    }

    // Redirect the stdout of Process two into the stdin of `cmd`, and return
    // the process created from `cmd`.
    fn pipe_input(&mut self,
                  cmd : Cmd,
                  two : Option<~run::Process>) -> Option<~run::Process> {
        match make_process(cmd, None, Some(1)) {
            Some(mut process) => {
                match two {
                    Some(mut p2) => {
                        let output = p2.finish_with_output();
                        if output.status.success() {
                            process.input().write(output.output);
                            process.close_input();
                            process.finish();
                        }
                        Some(~process)
                    }
                    None => {
                        println("No two remain.");
                        Some(~process)
                    }
                }
            }
            None => {
                None
            }
        }
    }

    // Make a new background process, and push it onto our stack of tracked
    // background processes.
    fn make_bg_process(&mut self, cmd : Cmd) {
        let name = cmd.program.to_owned();
        match BgProcess::new(cmd) {
            Some(mut process) => {
                match process.run() {
                    Some(pid) => {
                        println!("{:s} {:i}", name, pid);
                        self.processes.push(~process);
                    }
                    None => {
                    }
                }
            }
            None => {
            }
        }
    }
}

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;
    }
}

// Determine whether a command exists using "which".
fn cmd_exists(command : &Cmd) -> bool {
    let ret = run::process_output("which", [command.program.to_owned()]);
    return ret.expect("exit code error.").status.success();
}

fn split_words(word : &str) -> ~[~str] {
    word.split(' ').filter_map(
        |x| if x != "" { Some(x.to_owned()) } else { None }
        ).to_owned_vec()
}

fn make_process(cmd : Cmd,
                stdin: Option<i32>,
                stdout: Option<i32>) -> Option<run::Process> {
    maybe(FgProcess::new(cmd, stdin, stdout),
          |mut cmdprocess| cmdprocess.run())
}

fn parse_l_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('<').collect();
    let filename = pair[0].trim();
    match maybe(Cmd::new(pair[1].trim()), |c| make_process(c, None, Some(1))) {
        Some(mut process) => {
            match File::open_mode(&Path::new(filename),
                                    std::io::Append,
                                    std::io::ReadWrite) {
                Some(file) => {
                    let proc_input = process.input();
                    let mut file_buffer = BufferedReader::new(file);
                    proc_input.write(file_buffer.read_to_end());
                }
                None => {
                }
            }
        }
        None => {
        }
    }
}

fn write_output_to_file(output : std::run::ProcessOutput,
                        filename : &str) {
    if output.status.success() {
        match File::open_mode(&Path::new(filename),
                                std::io::Truncate,
                                std::io::Write)
        {
            Some(mut file) => {
                file.write(output.output);
            }
            None =>{
                println!("Opening {:s} failed!", filename);
            }
        }
    }
    else {
        println!("{:?}", output.error);
    }
}

fn parse_r_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('>').collect();
    let file = pair[0].trim();
    let cmd = Cmd::new(pair[1].trim());
    match maybe(cmd, |c| make_process(c, None, None)) {
        Some(mut process) => {
            write_output_to_file(
                process.finish_with_output(),
                file);
        }
        None => {
        }
    }
}

// Describes a computation that could fail.
// If v is Some(...), then f is called on v and the result is returned.
// Otherwise, None is returned.
fn maybe<A, B>(v : Option<A>, f : |A| -> Option<B>) -> Option<B> {
    match v {
        Some(v) => f(v),
        None    => None,
    }
}

// Same as maybe(v, f), but for &v.
fn borrowed_maybe<A, B>(v : &Option<A>, f : |&A| -> Option<B>) -> Option<B> {
    match *v {
        Some(ref v) => f(v),
        None    => None,
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => {
            let mut shell = Shell::new("");
            shell.run_cmdline(cmd_line);
        }
        None => {
            let mut shell = Shell::new("gash > ");
            shell.run();
        }
    }
}
<commit_msg>rename shell's run() to start()<commit_after>//
// gash.rs
// by Nathan Typanski
//
// 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;

use std::{run, os};
use std::io::buffered::BufferedReader;
use std::io::{stdin, stdio, File, Truncate, Write};
use std::io::process::ProcessExit;
use std::io::signal::{Listener, Interrupt};
use std::path::posix::Path;
use std::option::Option;
use std::task::try;
use std::run::Process;
use std::run::ProcessOptions;
use std::comm::Port;

use extra::getopts;

use std::libc::types::os::arch::posix88::pid_t;
use std::libc;

extern {
  pub fn kill(pid: libc::pid_t, sig: libc::c_int) -> libc::c_int;
}

// The basic unit for a command that could be run.
struct Cmd {
    program : ~str,
    argv : ~[~str],
}

impl Cmd {
    fn new(cmd_name: &str) -> Option<Cmd> {
        let mut argv: ~[~str] = split_words(cmd_name);
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            let argv : ~[~str] = argv;
            Some(Cmd {
                program : program,
                argv : argv,
            })
        }
        else {
            None
        }
    }
}

struct FgProcess {
    command     : ~str,
    args        : ~[~str],
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl FgProcess {
    fn new(cmd : Cmd,
           stdin : Option<i32>,
           stdout : Option<i32>)
        -> Option<FgProcess>
    {
        if (cmd_exists(&cmd)) {
            Some(FgProcess {
                command     : cmd.program.to_owned(),
                args        : cmd.argv.to_owned(),
                stdin       : stdin,
                stdout      : stdout,
            })
        }
        else { None }
    }

    fn run(&mut self) -> Option<Process> {
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        let options = ProcessOptions {
            env    : None,
            dir    : None,
            in_fd  : self.stdin,
            out_fd : self.stdout,
            err_fd : None,
        };
        Process::new(command, args, options)
    }
}

// Background processes are handled differently, but not *that* differently:
// we need to keep track of an ProcessExit port for determining whether a
// process has finished running, as well as a pid for the process (for killing
// it when the shell terminates).
struct BgProcess {
    command      : ~str,
    args         : ~[~str],
    exit_port    : Option<Port<ProcessExit>>,
    pid          : Option<i32>,
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl BgProcess {
    fn new(cmd : Cmd) -> Option<BgProcess> {
        if (cmd_exists(&cmd)) {
            Some(BgProcess {
                command: cmd.program.to_owned(),
                args: cmd.argv.to_owned(),
                exit_port: None,
                pid: None,
                stdin: None,
                stdout: None,
            })
        }
        else { None }
    }

    fn run(&mut self) -> Option<pid_t> {
        // Process exit ports; used for checking dead status.
        let (port, chan): (Port<ProcessExit>, Chan<ProcessExit>) = Chan::new();
        // Process ports; these don't leave this function and are used for
        // sending the PID out in the return value.
        let (pidport, pidchan): (Port<Option<pid_t>>, Chan<Option<pid_t>>)
                            = Chan::new();
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        spawn(proc() {
            let options = ProcessOptions {
                env    : None,
                dir    : None,
                in_fd  : None,
                out_fd : None,
                err_fd : None,
            };
            let maybe_process = Process::new(command, args, options);
            match maybe_process {
                Some(mut process) => {
                    // Send the pid out for the return value
                    pidchan.try_send_deferred(Some(process.get_id()));
                    chan.try_send_deferred(process.finish());
                }
                None => {
                    pidchan.try_send_deferred(None);
                }
            }
        });
        self.exit_port = Some(port);
        self.pid = pidport.recv();
        self.pid
    }
}

struct Shell {
    cmd_prompt : ~str,
    history    : ~[~str],
    processes  : ~[~BgProcess],
    broken : bool,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
            processes: ~[],
            broken: false,
        }
    }

    fn start(&mut self) {
        // Setup the interrupt handler. Has to happen here, or it won't
        // retain control over interrupts.
        let mut listener = Listener::new();
        listener.register(Interrupt);
        let port = listener.port;
        spawn(proc() {
            try(proc() {
                loop {
                    match port.recv_opt() {
                        Some(Interrupt) => {
                        }
                        None => {
                            break;
                        }
                        _ => {
                        }
                    }
                }
                return 0
            });
            return ();
        });

        self.display_prompt();
    }

    fn display_prompt(&mut self) {
        // Standard input reader
        let mut stdin = BufferedReader::new(stdin());
        // Show the prompt
        print(self.cmd_prompt);
        stdio::flush();

        let line = stdin.read_line().unwrap();
        let cmd_line = line.trim().to_owned();
        let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
        self.disown_dead();

        // Push commands onto the history
        match program {
            "" => {}
            _  => {
                self.push_hist(cmd_line)
            }
        }

        match program {
            "" =>  {
                self.display_prompt();
            }
            "exit" =>  {
                self.kill_all();
            }
            "history" => {
                self.show_hist();
                self.display_prompt();
            }
            "jobs" => {
                self.jobs();
                self.display_prompt();
            }
            "cd" =>  {
                self.chdir(cmd_line);
                self.display_prompt();
            }
            _ => {
                self.run_cmdline(cmd_line);
                self.display_prompt();
            }
        }
    }

    // Nice extra feature: list running jobs.
    fn jobs(&mut self) {
        for cmd in self.processes.iter() {
            print!("{:s}", cmd.command);
            match cmd.pid {
                Some(pid) => {
                    println!(" {:i}", pid);
                }
                None => {
                    println("");
                }
            }
        }
    }

    // Remove dead processes from the list of processes.
    fn disown_dead(&mut self) {
        let mut dead : ~[uint];
        dead = ~[];
        let mut i = 0;
        for cmd in self.processes.iter() {
            borrowed_maybe(&cmd.exit_port, |port| match port.try_recv() {
                Some(_) => {dead.push(i); Some(i)},
                _ => None,
            });
            i += 1;
        }
        for &p in dead.iter() {
            self.processes.remove(p);
        }
    }

    fn kill_all(&mut self) {
        for p in self.processes.iter() {
            match p.pid {
                Some(pid) => {
                    unsafe {
                        // Kill perhaps isn't the best way to do this, but
                        // without it we have no way of killing our background
                        // processes with only the PID - we'd need the process
                        // object itself, and that can't be moved out of the
                        // spawn() that it's trapped inside.
                        kill(pid, 15);
                    }
                }
                None => {
                }
            }
        }
    }

    // Push a new command onto history.
    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] = split_words(cmd_line);
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    // Determine the type of the current block, and send it to the right
    // parsing function.
    fn run_cmdline(&mut self, cmd_line: &str) {
        if cmd_line.contains_char('>') {
            parse_r_redirect(cmd_line);
        }
        else if cmd_line.contains_char('<') {
            parse_l_redirect(cmd_line);
        }
        else if cmd_line.contains_char('|') {
            self.parse_pipeline(cmd_line);
        }
        else {
            self.parse_process(cmd_line);
        }
    }

    // Parse a new lone process. Background/foreground it appropriately.
    fn parse_process(&mut self, cmd_line : &str) -> Option<Process>{
        maybe(Cmd::new(cmd_line), |cmd| {
            if (cmd.argv.len() > 0 && cmd.argv.last() == &~"&") {
                let mut argv = cmd.argv.to_owned();
                argv.pop();
                self.make_bg_process(Cmd{
                    program:cmd.program,
                    argv:argv});
                None
            }
            else {
                make_process(cmd, Some(0), Some(1))
            }
        })
    }

    // Parse a process pipeline, and redirect stdin/stdout appropriately.
    fn parse_pipeline(&mut self, cmd_line : &str) -> Option<~run::Process> {
        let pair : ~[&str] = cmd_line.rsplitn('|', 1).collect();
        maybe(Cmd::new(pair[0].trim()), |cmd| {
            if pair.len() > 1 {
                let two = self.parse_pipeline(pair[1].trim());
                self.pipe_input(cmd, two)
            }
            else {
                maybe(make_process(cmd, None, None), |process| Some(~process))
            }
        })
    }

    // Redirect the stdout of Process two into the stdin of `cmd`, and return
    // the process created from `cmd`.
    fn pipe_input(&mut self,
                  cmd : Cmd,
                  two : Option<~run::Process>) -> Option<~run::Process> {
        match make_process(cmd, None, Some(1)) {
            Some(mut process) => {
                match two {
                    Some(mut p2) => {
                        let output = p2.finish_with_output();
                        if output.status.success() {
                            process.input().write(output.output);
                            process.close_input();
                            process.finish();
                        }
                        Some(~process)
                    }
                    None => {
                        println("No two remain.");
                        Some(~process)
                    }
                }
            }
            None => {
                None
            }
        }
    }

    // Make a new background process, and push it onto our stack of tracked
    // background processes.
    fn make_bg_process(&mut self, cmd : Cmd) {
        let name = cmd.program.to_owned();
        match BgProcess::new(cmd) {
            Some(mut process) => {
                match process.run() {
                    Some(pid) => {
                        println!("{:s} {:i}", name, pid);
                        self.processes.push(~process);
                    }
                    None => {
                    }
                }
            }
            None => {
            }
        }
    }
}

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;
    }
}

// Determine whether a command exists using "which".
fn cmd_exists(command : &Cmd) -> bool {
    let ret = run::process_output("which", [command.program.to_owned()]);
    return ret.expect("exit code error.").status.success();
}

fn split_words(word : &str) -> ~[~str] {
    word.split(' ').filter_map(
        |x| if x != "" { Some(x.to_owned()) } else { None }
        ).to_owned_vec()
}

fn make_process(cmd : Cmd,
                stdin: Option<i32>,
                stdout: Option<i32>) -> Option<run::Process> {
    maybe(FgProcess::new(cmd, stdin, stdout),
          |mut cmdprocess| cmdprocess.run())
}

fn parse_l_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('<').collect();
    let filename = pair[0].trim();
    match maybe(Cmd::new(pair[1].trim()), |c| make_process(c, None, Some(1))) {
        Some(mut process) => {
            match File::open_mode(&Path::new(filename),
                                    std::io::Append,
                                    std::io::ReadWrite) {
                Some(file) => {
                    let proc_input = process.input();
                    let mut file_buffer = BufferedReader::new(file);
                    proc_input.write(file_buffer.read_to_end());
                }
                None => {
                }
            }
        }
        None => {
        }
    }
}

fn write_output_to_file(output : std::run::ProcessOutput,
                        filename : &str) {
    if output.status.success() {
        match File::open_mode(&Path::new(filename),
                                std::io::Truncate,
                                std::io::Write)
        {
            Some(mut file) => {
                file.write(output.output);
            }
            None =>{
                println!("Opening {:s} failed!", filename);
            }
        }
    }
    else {
        println!("{:?}", output.error);
    }
}

fn parse_r_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('>').collect();
    let file = pair[0].trim();
    let cmd = Cmd::new(pair[1].trim());
    match maybe(cmd, |c| make_process(c, None, None)) {
        Some(mut process) => {
            write_output_to_file(
                process.finish_with_output(),
                file);
        }
        None => {
        }
    }
}

// Describes a computation that could fail.
// If v is Some(...), then f is called on v and the result is returned.
// Otherwise, None is returned.
fn maybe<A, B>(v : Option<A>, f : |A| -> Option<B>) -> Option<B> {
    match v {
        Some(v) => f(v),
        None    => None,
    }
}

// Same as maybe(v, f), but for &v.
fn borrowed_maybe<A, B>(v : &Option<A>, f : |&A| -> Option<B>) -> Option<B> {
    match *v {
        Some(ref v) => f(v),
        None    => None,
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => {
            let mut shell = Shell::new("");
            shell.run_cmdline(cmd_line);
        }
        None => {
            let mut shell = Shell::new("gash > ");
            shell.start();
        }
    }
}
<|endoftext|>