pvjscript.Main Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rcslib Show documentation
Show all versions of rcslib Show documentation
NIST Real-Time Control Systems Library including Posemath, NML communications and Java Plotter
The newest version!
/*
* Main.java
*
* Created on May 25, 2011, 8:34:34 AM
*/
package pvjscript;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingQueue;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollBar;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.AttributeSet;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Style;
/**
*
* @author shackle
*/
public class Main extends javax.swing.JFrame {
/** Creates new form Main */
public Main() {
initComponents();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// //GEN-BEGIN:initComponents
private void initComponents() {
jDialogEnvp = new javax.swing.JDialog();
jScrollPaneEnvpTable = new javax.swing.JScrollPane();
jTableEnvp = new javax.swing.JTable();
buttonGroupVw = new javax.swing.ButtonGroup();
jScrollPane1 = new javax.swing.JScrollPane();
jTextPane1 = new javax.swing.JTextPane();
jTextFieldCmd = new javax.swing.JTextField();
jMenuBar1 = new javax.swing.JMenuBar();
jMenu1 = new javax.swing.JMenu();
jMenuItemOpen = new javax.swing.JMenuItem();
jMenuProcess = new javax.swing.JMenu();
jMenu2 = new javax.swing.JMenu();
jRadioButtonMenuItemViewStdOut = new javax.swing.JRadioButtonMenuItem();
jRadioButtonMenuItemViewStdErr = new javax.swing.JRadioButtonMenuItem();
jRadioButtonMenuItemViewBoth = new javax.swing.JRadioButtonMenuItem();
jRadioButtonMenuItemViewDebug = new javax.swing.JRadioButtonMenuItem();
jMenuTools = new javax.swing.JMenu();
jMenuItem1 = new javax.swing.JMenuItem();
jMenuItem2 = new javax.swing.JMenuItem();
jMenuOptions = new javax.swing.JMenu();
jCheckBoxMenuItemAutoScroll = new javax.swing.JCheckBoxMenuItem();
jMenuItemSetScrollLimit = new javax.swing.JMenuItem();
jTableEnvp.setAutoCreateRowSorter(true);
jTableEnvp.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{null, null},
{null, null},
{null, null},
{null, null}
},
new String [] {
"Env Variable", "Env Value"
}
) {
Class[] types = new Class [] {
java.lang.String.class, java.lang.String.class
};
boolean[] canEdit = new boolean [] {
false, false
};
public Class getColumnClass(int columnIndex) {
return types [columnIndex];
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return canEdit [columnIndex];
}
});
jScrollPaneEnvpTable.setViewportView(jTableEnvp);
javax.swing.GroupLayout jDialogEnvpLayout = new javax.swing.GroupLayout(jDialogEnvp.getContentPane());
jDialogEnvp.getContentPane().setLayout(jDialogEnvpLayout);
jDialogEnvpLayout.setHorizontalGroup(
jDialogEnvpLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jDialogEnvpLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPaneEnvpTable, javax.swing.GroupLayout.DEFAULT_SIZE, 419, Short.MAX_VALUE)
.addContainerGap())
);
jDialogEnvpLayout.setVerticalGroup(
jDialogEnvpLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jDialogEnvpLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPaneEnvpTable, javax.swing.GroupLayout.DEFAULT_SIZE, 372, Short.MAX_VALUE)
.addContainerGap())
);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent evt) {
formWindowClosing(evt);
}
public void windowClosed(java.awt.event.WindowEvent evt) {
formWindowClosed(evt);
}
});
jTextPane1.setEditable(false);
jScrollPane1.setViewportView(jTextPane1);
jTextFieldCmd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jTextFieldCmdActionPerformed(evt);
}
});
jMenu1.setText("File");
jMenuItemOpen.setText("Open ...");
jMenuItemOpen.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItemOpenActionPerformed(evt);
}
});
jMenu1.add(jMenuItemOpen);
jMenuBar1.add(jMenu1);
jMenuProcess.setText("Process");
jMenuBar1.add(jMenuProcess);
jMenu2.setText("View");
buttonGroupVw.add(jMenu2);
buttonGroupVw.add(jRadioButtonMenuItemViewStdOut);
jRadioButtonMenuItemViewStdOut.setText("View Std Out");
jRadioButtonMenuItemViewStdOut.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jRadioButtonMenuItemViewStdOutActionPerformed(evt);
}
});
jMenu2.add(jRadioButtonMenuItemViewStdOut);
buttonGroupVw.add(jRadioButtonMenuItemViewStdErr);
jRadioButtonMenuItemViewStdErr.setText("View Std Err");
jRadioButtonMenuItemViewStdErr.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jRadioButtonMenuItemViewStdErrActionPerformed(evt);
}
});
jMenu2.add(jRadioButtonMenuItemViewStdErr);
buttonGroupVw.add(jRadioButtonMenuItemViewBoth);
jRadioButtonMenuItemViewBoth.setSelected(true);
jRadioButtonMenuItemViewBoth.setText("View Both Std Out and Err");
jRadioButtonMenuItemViewBoth.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jRadioButtonMenuItemViewBothActionPerformed(evt);
}
});
jMenu2.add(jRadioButtonMenuItemViewBoth);
buttonGroupVw.add(jRadioButtonMenuItemViewDebug);
jRadioButtonMenuItemViewDebug.setText("View All and Debug");
jRadioButtonMenuItemViewDebug.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jRadioButtonMenuItemViewDebugActionPerformed(evt);
}
});
jMenu2.add(jRadioButtonMenuItemViewDebug);
jMenuBar1.add(jMenu2);
jMenuTools.setText("Tools");
jMenuItem1.setText("Show Environment ...");
jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem1ActionPerformed(evt);
}
});
jMenuTools.add(jMenuItem1);
jMenuItem2.setText("Kill this process");
jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem2ActionPerformed(evt);
}
});
jMenuTools.add(jMenuItem2);
jMenuBar1.add(jMenuTools);
jMenuOptions.setText("Options");
jCheckBoxMenuItemAutoScroll.setSelected(true);
jCheckBoxMenuItemAutoScroll.setText("Automatically Scroll");
jMenuOptions.add(jCheckBoxMenuItemAutoScroll);
jMenuItemSetScrollLimit.setText("Set Scroll Limit ...");
jMenuItemSetScrollLimit.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItemSetScrollLimitActionPerformed(evt);
}
});
jMenuOptions.add(jMenuItemSetScrollLimit);
jMenuBar1.add(jMenuOptions);
setJMenuBar(jMenuBar1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jTextFieldCmd, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 244, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jTextFieldCmd, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);
pack();
}// //GEN-END:initComponents
private void jMenuItemOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemOpenActionPerformed
this.BrowseOpenScriptFile();
}//GEN-LAST:event_jMenuItemOpenActionPerformed
private void setViewState() {
if (this.jRadioButtonMenuItemViewStdOut.isSelected()) {
this.vw_state = ViewState.ViewStdOut;
} else if (this.jRadioButtonMenuItemViewStdErr.isSelected()) {
this.vw_state = ViewState.ViewStdErr;
} else if (this.jRadioButtonMenuItemViewBoth.isSelected()) {
this.vw_state = ViewState.ViewStdOutAndStdErr;
} else if (this.jRadioButtonMenuItemViewDebug.isSelected()) {
this.vw_state = ViewState.ViewStdOutAndStdErrAndDebug;
} else {
System.err.println("Bad radio button state!");
this.vw_state = ViewState.ViewStdOutAndStdErr;
this.jRadioButtonMenuItemViewBoth.setSelected(true);
}
this.updateTextPane();
}
private void jRadioButtonMenuItemViewStdOutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonMenuItemViewStdOutActionPerformed
setViewState();
}//GEN-LAST:event_jRadioButtonMenuItemViewStdOutActionPerformed
private void jRadioButtonMenuItemViewStdErrActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonMenuItemViewStdErrActionPerformed
setViewState();
}//GEN-LAST:event_jRadioButtonMenuItemViewStdErrActionPerformed
private void jRadioButtonMenuItemViewBothActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonMenuItemViewBothActionPerformed
setViewState();
}//GEN-LAST:event_jRadioButtonMenuItemViewBothActionPerformed
private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed
this.ShowEnvironment();
}//GEN-LAST:event_jMenuItem1ActionPerformed
private void jMenuItemSetScrollLimitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemSetScrollLimitActionPerformed
String s = JOptionPane.showInputDialog("Max Characters to Keep?", ProcessView.BUF_LIMIT);
if (s != null) {
ProcessView.BUF_LIMIT = Integer.valueOf(s);
}
}//GEN-LAST:event_jMenuItemSetScrollLimitActionPerformed
private void jTextFieldCmdActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTextFieldCmdActionPerformed
try {
if (null == this.mainThread) {
this.startMainThread();
}
String l = this.jTextFieldCmd.getText();
if (null == scriptPv) {
this.setDir(new File(System.getProperty("user.dir")));
this.initEnvp();
scriptPv = this.createPv(l);
}
CurrentPv = this.scriptPv;
scriptPv.appendOut("cmd> " + l);
this.lineQueue.add(this.jTextFieldCmd.getText());
this.updateTextPane();
this.jTextFieldCmd.setText("");
} catch (Exception exception) {
exception.printStackTrace();
}
}//GEN-LAST:event_jTextFieldCmdActionPerformed
private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed
this.close();
}//GEN-LAST:event_formWindowClosed
private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
this.close();
}//GEN-LAST:event_formWindowClosing
private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed
if (null != CurrentPv) {
CurrentPv.close();
}
}//GEN-LAST:event_jMenuItem2ActionPerformed
private void jRadioButtonMenuItemViewDebugActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonMenuItemViewDebugActionPerformed
setViewState();
}//GEN-LAST:event_jRadioButtonMenuItemViewDebugActionPerformed
private enum ViewState {
ViewStdOut,
ViewStdErr,
ViewStdOutAndStdErr,
ViewStdOutAndStdErrAndDebug,
};
private ViewState vw_state = ViewState.ViewStdOutAndStdErr;
AttributeSet origCa = null;
DefaultStyledDocument outDoc = new DefaultStyledDocument();
DefaultStyledDocument errDoc = new DefaultStyledDocument();
private void updateTextPane() {
if (origCa == null) {
origCa = this.jTextPane1.getCharacterAttributes();
}
if (null == this.CurrentPv) {
this.jTextPane1.setText("");
} else {
switch (vw_state) {
case ViewStdOut:
this.jTextPane1.setStyledDocument(outDoc);
this.jTextPane1.setForeground(Color.black);
this.jTextPane1.setCharacterAttributes(this.CurrentPv.getOutStyle(), true);
this.jTextPane1.setText(this.CurrentPv.getOut());
this.jTextPane1.setForeground(Color.black);
this.jTextPane1.setCharacterAttributes(this.CurrentPv.getOutStyle(), true);
break;
case ViewStdErr:
this.jTextPane1.setStyledDocument(errDoc);
this.jTextPane1.setForeground(Color.red);
this.jTextPane1.setCharacterAttributes(this.CurrentPv.getErrStyle(), true);
this.jTextPane1.setText(this.CurrentPv.getErr());
this.jTextPane1.setForeground(Color.red);
this.jTextPane1.setCharacterAttributes(this.CurrentPv.getErrStyle(), true);
break;
case ViewStdOutAndStdErr:
//this.jTextPane1.setText(null);
this.jTextPane1.setCharacterAttributes(origCa, true);
this.jTextPane1.setStyledDocument(this.CurrentPv.getOutPlusErr());
break;
case ViewStdOutAndStdErrAndDebug:
//this.jTextPane1.setText(null);
this.jTextPane1.setCharacterAttributes(origCa, true);
this.jTextPane1.setStyledDocument(this.CurrentPv.getOutPlusErrPlusDebug());
break;
}
}
}
protected String LastScriptDir;
/**
* Get the value of LastScriptDir
*
* @return the value of LastScriptDir
*/
public String getLastScriptDir() {
return LastScriptDir;
}
/**
* Set the value of LastScriptDir
*
* @param LastScriptDir new value of LastScriptDir
*/
public void setLastScriptDir(String LastScriptDir) {
this.LastScriptDir = LastScriptDir;
}
private void BrowseOpenScriptFile() {
try {
JFileChooser chooser = new JFileChooser();
if (null != this.LastScriptDir) {
chooser.setCurrentDirectory(new File(this.LastScriptDir));
}
FileNameExtensionFilter pvjscript_file_filter = new FileNameExtensionFilter("pvjscript", "pvjscript");
chooser.addChoosableFileFilter(pvjscript_file_filter);
chooser.setFileFilter(pvjscript_file_filter);
chooser.setMultiSelectionEnabled(true);
int returnVal = chooser.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File fa[] = chooser.getSelectedFiles();
for (int i = 0; i < fa.length; i++) {
final File f = fa[i];
System.out.println("You chose to open this file: "
+ f.getPath());
File dir1 = chooser.getCurrentDirectory();
this.setLastScriptDir(dir1.getAbsolutePath());
if (null == this.mainThread) {
this.startMainThread();
}
this.lineQueue.add(f.getCanonicalPath());
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
private void ShowEnvironment() {
this.jDialogEnvp.setVisible(false);
this.jDialogEnvp.setTitle("Environment for " + CurrentPv);
DefaultTableModel model = (DefaultTableModel) this.jTableEnvp.getModel();
String envpA[] = envp;
if (null != this.CurrentPv) {
envpA = this.CurrentPv.getEnvp();
}
if (null != envpA) {
model.setRowCount(envpA.length);
for (int i = 0; i < envpA.length; i++) {
int eqindex = envpA[i].indexOf('=');
if (eqindex > 0) {
String var = envpA[i].substring(0, eqindex);
String val = envpA[i].substring(eqindex + 1);
model.setValueAt(var, i, 0);
model.setValueAt(val, i, 1);
}
}
}
this.jDialogEnvp.pack();
this.jDialogEnvp.setVisible(true);
}
protected LinkedList JobsList;
/**
* Get the value of JobsList
*
* @return the value of JobsList
*/
public LinkedList getJobsList() {
return JobsList;
}
/**
* Set the value of JobsList
*
* @param JobsList new value of JobsList
*/
public void setJobsList(LinkedList JobsList) {
this.JobsList = JobsList;
}
protected ProcessView CurrentPv;
/**
* Get the value of CurrentPv
*
* @return the value of CurrentPv
*/
public ProcessView getCurrentPv() {
return CurrentPv;
}
/**
* Set the value of CurrentPv
*
* @param CurrentPv new value of CurrentPv
*/
public void setCurrentPv(ProcessView CurrentPv) {
this.CurrentPv = CurrentPv;
}
String val0 = "";
HashMap tmpVars = null;
private String getval(String s) {
try {
if (s.compareTo("0") == 0) {
return val0;
}
if (null != tmpVars) {
String v = tmpVars.get(s);
if (null != v) {
return v;
}
}
if (null != envp) {
for (int i = 0; i < envp.length; i++) {
if (envp[i].startsWith(s + "=")) {
return envp[i].substring(s.length() + 1);
}
}
}
java.util.Properties p = System.getProperties();
if (p != null) {
String v = p.getProperty(s);
if (v != null) {
return v;
}
}
String ev = System.getenv(s);
if (null != ev) {
return ev;
}
if (s.compareTo("RCSLIB_DIR") == 0) {
return this.find_rcslib_dir();
}
return this.query_val(s);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public void close() {
try {
if (null != this.JobsList) {
for (final ProcessView pv : JobsList) {
pv.close();
}
}
this.JobsList = null;
} catch (Exception e) {
e.printStackTrace();
}
}
protected void finalize() throws Throwable {
super.finalize();
close();
}
public void updateProcessMenu() {
this.jMenuProcess.removeAll();
if (null != this.JobsList) {
for (final ProcessView pv : JobsList) {
JMenuItem jmi = new JMenuItem(pv.toString());
jmi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
CurrentPv = pv;
updateTextPane();
}
});
this.jMenuProcess.add(jmi);
}
}
}
protected File dir;
/**
* Get the value of dir
*
* @return the value of dir
*/
public File getDir() {
return dir;
}
/**
* Set the value of dir
*
* @param dir new value of dir
*/
public void setDir(File dir) {
this.dir = dir;
if (null != scriptPv) {
scriptPv.setDir(dir);
}
}
protected String[] envp;
/**
* Get the value of envp
*
* @return the value of envp
*/
public String[] getEnvp() {
return envp;
}
/**
* Set the value of envp
*
* @param envp new value of envp
*/
public void setEnvp(String[] envp) {
this.envp = envp;
if (null != scriptPv) {
scriptPv.setEnvp(envp);
}
}
private void scrollToEnd() {
JScrollBar vbar = this.jScrollPane1.getVerticalScrollBar();
vbar.setValue(vbar.getMaximum());
}
private ProcessView createPv(String l) {
ProcessView pv = new ProcessView(l.trim());
if (null != dir) {
pv.setDir(dir);
}
if (null != envp) {
pv.setEnvp(envp.clone());
}
pv.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getSource() == CurrentPv
|| null == CurrentPv) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
updateTextPane();
if (jCheckBoxMenuItemAutoScroll.isSelected()) {
scrollToEnd();
}
}
});
}
}
});
return pv;
}
public String RunCmd(String l) throws Exception {
String piped_cmds[] = l.split("[|]");
if (null != piped_cmds && piped_cmds.length > 1) {
ProcessView pva[] = new ProcessView[piped_cmds.length];
for (int i = 0; i < piped_cmds.length; i++) {
pva[i] = this.createPv(piped_cmds[i]);
//this.addJob(pva[i]);
}
for (int i = piped_cmds.length - 1; i >= 0; i--) {
if (i < piped_cmds.length - 1) {
pva[i].setPipedOutput(pva[i + 1].getOutputStream());
}
pva[i].Start(scriptPv);
}
pva[0].waitFor();
for (int i = 0; i < pva.length; i++) {
pva[i].close();
}
String r = pva[pva.length - 1].getOut();
return r;
}
switch (checkBuiltIns(this.splitArgs(l))) {
case 0:
return builtin_output;
case 1:
return builtin_output;
}
ProcessView pv = this.createPv(l);
pv.Start(scriptPv);
pv.waitFor();
pv.close();
Thread.sleep(200);
return pv.getOut();
}
private String builtin_output = "";
private String replaceVar(String in) {
if (in.startsWith("$")) {
String aftervar = in.substring(1);
String var = "";
while (aftervar.length() > 0
&& Character.isJavaIdentifierPart(aftervar.charAt(0))) {
var += aftervar.substring(0, 1);
aftervar = aftervar.substring(1);
}
in = getval(var) + aftervar;
} else if (in.startsWith("2>/dev/null")) {
in = "";
}
return in;
}
private String[] splitArgs(String l) {
LinkedList argsl = new LinkedList();
boolean inside_double_quotes = false;
boolean inside_single_quotes = false;
boolean inside_back_quotes = false;
boolean quoted_arg = false;
String next_arg = "";
while (l.length() > 0) {
char c = l.charAt(0);
// if (c == '\\'
// && l.charAt(1) != '*'
// && l.charAt(1) != '?') {
// next_arg += l.charAt(1);
// l = l.substring(2);
// continue;
// }
if (c == '`') {
inside_back_quotes = !inside_back_quotes;
quoted_arg = true;
next_arg += c;
l = l.substring(1);
continue;
}
if (inside_back_quotes) {
next_arg += c;
l = l.substring(1);
continue;
}
if (c == '\'') {
inside_single_quotes = !inside_single_quotes;
quoted_arg = true;
l = l.substring(1);
continue;
}
if (inside_single_quotes) {
next_arg += c;
l = l.substring(1);
continue;
}
if (c == '"') {
inside_double_quotes = !inside_double_quotes;
quoted_arg = true;
l = l.substring(1);
continue;
}
if (inside_double_quotes) {
next_arg += c;
l = l.substring(1);
continue;
}
if (c == ' ' || c == '\t') {
if (next_arg.length() > 0) {
if (!quoted_arg) {
argsl.add(this.replaceVar(next_arg));
} else {
argsl.add(next_arg);
}
}
next_arg = "";
l = l.substring(1);
quoted_arg = false;
continue;
}
next_arg += c;
l = l.substring(1);
}
if (next_arg.length() > 0) {
if (!quoted_arg) {
argsl.add(this.replaceVar(next_arg));
} else {
argsl.add(next_arg);
}
}
String args[] = new String[argsl.size()];
return argsl.toArray(args);
}
private Stack ifStateStack = new Stack();
private boolean current_ifstate = true;
File strToFile(String s) {
File f = new File(s);
if (f.isAbsolute() && f.getParentFile().exists()) {
return f;
}
if (s.startsWith("./")) {
s = s.substring(2);
}
String pathElem[] = s.split("/+");
if (s.startsWith("/")) {
f = new File(File.separator + pathElem[0]);
} else {
if (pathElem[0].compareTo("..") == 0) {
f = dir.getParentFile();
} else {
f = new File(dir, pathElem[0]);
}
}
for (int i = 1; i < pathElem.length; i++) {
if (pathElem[i].compareTo("..") == 0) {
f = f.getParentFile();
} else {
f = new File(f, pathElem[i]);
}
}
return f;
}
String arrayToStr(String args[]) {
return arrayToStr(args, 0);
}
String arrayToStr(String args[], int starting_arg) {
if (args == null || args.length < 1) {
return "";
}
String out = args[starting_arg];
for (int i = starting_arg + 1; i < args.length; i++) {
out += " " + args[i];
}
return out;
}
private class forEntry {
long seek_to;
String var;
String argsleft[];
}
private Stack forStack = null;
private boolean last_cmd_was_builtin = false;
private int checkBuiltIns(String args[]) throws Exception {
builtin_output = "";
last_cmd_was_builtin = true;
if (args[0].startsWith("\\")) {
args[0] = args[0].substring(1);
}
if (args[0].compareTo("waitfor") == 0) {
if (args.length < 3) {
appendErr("bad waitfor syntax: need 2 args :" + arrayToStr(args));
return 0;
}
long timeout = Long.valueOf(args[1]) * 1000;
final String fname = args[2];
File wf = this.strToFile(fname);
if(!wf.exists() && this.last_line_through_exception) {
if(JOptionPane.showConfirmDialog(this, "Wait for "+wf.toString()+"?") != JOptionPane.YES_OPTION) {
return 0;
}
}
long stime = System.currentTimeMillis();
appendDebug("waiting up to " + (timeout / 1000) + " seconds for the file \"" + wf.getCanonicalPath() + "\" to exist ...");
while (!wf.exists()
&& (timeout < 0
|| System.currentTimeMillis() - stime < timeout)) {
Thread.sleep(200);
wf = this.strToFile(fname);
}
if (timeout > 0
&& System.currentTimeMillis() - stime > timeout) {
appendErr("Timed out waiting for " + wf.getAbsolutePath());
if (JOptionPane.showConfirmDialog(this, "Timed out waiting for " + fname + ". Continue?") != JOptionPane.YES_OPTION) {
return 1;
}
}
return 0;
} else if (args[0].compareTo("cd") == 0) {
if (args.length != 2) {
appendErr("bad cd syntax: need 1 args :" + Arrays.toString(args));
return 0;
}
File f = this.strToFile(args[1]);
if (!f.exists()) {
appendErr(f.getCanonicalPath() + " does not exist.");
return 0;
}
if (!f.isDirectory()) {
appendErr(f.getCanonicalPath() + " does not exist.");
return 0;
}
this.setDir(f);
return 0;
} else if (args[0].compareTo("dirname") == 0) {
File tf = strToFile(args[1]);
builtin_output = tf.getParentFile().getCanonicalPath();
return 0;
} else if (args[0].compareTo("echo") == 0) {
builtin_output = args[1];
for (int i = 2; i < args.length; i++) {
builtin_output += " " + args[i];
}
return 0;
} else if (args[0].compareTo("export") == 0) {
for (int i = 1; i < args.length; i++) {
int eqindex = args[i].indexOf('=');
if (eqindex > 0) {
this.addEnvVar(args[i].substring(0, eqindex), args[i].substring(eqindex + 1));
}
}
return 0;
} else if (args[0].compareTo("exit") == 0) {
return 1;
} else if (args[0].compareTo("rm") == 0) {
for (int i = 1; i < args.length; i++) {
if (args[i].startsWith("-")) {
continue;
}
File f = this.strToFile(args[i]);
if (f.exists()) {
f.delete();
} else {
this.appendErr("rm: " + f.getCanonicalPath() + " does not exist.");
}
}
return 0;
} else if (args[0].compareTo("if") == 0) {
if (args[1].compareTo("test") == 0) {
for (int i = 2; i < args.length; i++) {
if (args[i].compareTo("!") == 0) {
current_ifstate = !current_ifstate;
} else if (args[i].compareTo("-o") == 0) {
if (current_ifstate) {
break;
}
current_ifstate = true;
} else if (args[i].compareTo("-a") == 0) {
if (!current_ifstate) {
break;
}
} else if (args[i].compareTo("-f") == 0) {
if (i >= args.length - 1) {
appendErr("bad test arguments");
return 1;
}
i++;
File fi = strToFile(args[i]);
if (!fi.exists() || fi.isDirectory()) {
current_ifstate = !current_ifstate;
}
} else if (args[i].compareTo("-e") == 0) {
if (i >= args.length - 1) {
appendErr("bad test arguments");
return 1;
}
i++;
File fi = strToFile(args[i]);
if (!fi.exists()) {
current_ifstate = !current_ifstate;
}
} else if (args[i].compareTo("-d") == 0) {
if (i >= args.length - 1) {
appendErr("bad test arguments");
return 1;
}
i++;
File fi = strToFile(args[i]);
if (!fi.exists() || !fi.isDirectory()) {
current_ifstate = !current_ifstate;
}
} else if (args[i].compareTo("-w") == 0) {
if (i >= args.length - 1) {
appendErr("bad test arguments");
return 1;
}
i++;
File fi = strToFile(args[i]);
if (!fi.exists() || !fi.canWrite()) {
current_ifstate = !current_ifstate;
}
} else if (args[i].compareTo("=") == 0) {
if (i >= args.length - 1 || i < 3) {
appendErr("bad test arguments");
return 1;
}
i++;
if (args[i - 2].compareTo(args[i]) != 0) {
current_ifstate = !current_ifstate;
}
} else if (args[i].compareTo("!=") == 0) {
if (i >= args.length - 1 || i < 3) {
appendErr("bad test arguments");
return 1;
}
i++;
if (args[i - 2].compareTo(args[i]) == 0) {
current_ifstate = !current_ifstate;
}
}
}
} else {
ProcessView pv = this.createPv(arrayToStr(Arrays.copyOfRange(args, 1, args.length)));
pv.Start(scriptPv);
current_ifstate = (pv.waitFor() == 0);
}
this.ifStateStack.push(current_ifstate);
return 0;
} else if (args[0].compareTo("else") == 0) {
if (this.ifStateStack.isEmpty()) {
appendErr("else without matching if");
return 1;
}
current_ifstate = !this.ifStateStack.pop();
this.ifStateStack.push(current_ifstate);
return 0;
} else if (args[0].compareTo("fi") == 0) {
if (this.ifStateStack.isEmpty()) {
appendErr("fi without matching if");
return 1;
}
this.ifStateStack.pop();
if (this.ifStateStack.isEmpty()) {
current_ifstate = true;
} else {
current_ifstate = this.ifStateStack.pop();
this.ifStateStack.push(current_ifstate);
}
return 0;
} else if (args[0].compareTo("for") == 0) {
forEntry fe = new forEntry();
fe.seek_to = this.script_line_num;
fe.argsleft = Arrays.copyOfRange(args, 3, args.length);
fe.var = args[1];
this.appendDebug("for: fe.argsleft="+fe.argsleft.length+" \""+Arrays.toString(fe.argsleft)+"\"");
this.appendDebug("for: fe.var="+fe.var);
this.appendDebug("for: fe.seek_to="+fe.seek_to);
if (fe.argsleft.length > 0) {
if (null == forStack) {
forStack = new Stack();
}
forStack.push(fe);
this.addTmpVar(fe.var, fe.argsleft[0]);
}
return 0;
} else if (args[0].compareTo("done") == 0) {
if (null == this.forStack || this.forStack.isEmpty()) {
appendErr("done without matching for");
}
forEntry fe = forStack.pop();
this.appendDebug("done: fe.argsleft="+fe.argsleft.length+" \""+Arrays.toString(fe.argsleft)+"\"");
this.appendDebug("done: fe.var="+fe.var);
this.appendDebug("done: fe.seek_to="+fe.seek_to);
if (fe.argsleft.length > 1) {
if (null != script_reader) {
script_reader.close();
}
this.script_reader = new BufferedReader(new FileReader(this.script_file));
for (int i = 0; i < fe.seek_to-1; i++) {
this.script_reader.readLine();
//System.err.println(i + ":Skipping " + this.script_reader.readLine());
}
this.appendDebug("done: returning to line after:"+this.script_reader.readLine());
this.script_line_num = (int) fe.seek_to;
fe.argsleft = Arrays.copyOfRange(fe.argsleft, 1, fe.argsleft.length);
if (null == forStack) {
forStack = new Stack();
}
forStack.push(fe);
this.addTmpVar(fe.var, fe.argsleft[0]);
} else if (forStack.isEmpty()) {
forStack = null;
}
return 0;
} else if (args[0].indexOf('=') > 0) {
int eqindex = args[0].indexOf('=');
if (eqindex > 0) {
this.addTmpVar(args[0].substring(0, eqindex), args[0].substring(eqindex + 1)
+ " " + this.arrayToStr(Arrays.copyOfRange(args, 1, args.length)));
return 0;
}
}
last_cmd_was_builtin = false;
return -1;
}
private ProcessView scriptPv = null;
private void addJob(ProcessView pv) {
if (null == JobsList) {
JobsList = new LinkedList();
}
JobsList.add(pv);
updateProcessMenu();
}
String[] expandFileGlobs(String args[]) {
LinkedList lst = new LinkedList();
for (int i = 0; i < args.length; i++) {
if (args[i].indexOf('*') >= 0 || args[i].indexOf('?') >= 0 || args[i].indexOf('/') >= 0) {
File f = this.strToFile(args[i]);
File fp = f.getParentFile();
if (fp.exists()) {
File fa[] = fp.listFiles();
if(null == fa) {
lst.add(args[i]);
continue;
}
String pattern = f.getName();
pattern = pattern.replaceAll("\\*", ".*");
pattern = pattern.replaceAll("\\?", ".");
for (int j = 0; j < fa.length; j++) {
if (fa[j].getName().matches(pattern)) {
lst.add(fa[j].toString());
}
}
continue;
} else {
lst.add(args[i]);
}
}
lst.add(args[i]);
}
String new_args[] = new String[lst.size()];
return lst.toArray(new_args);
}
LinkedBlockingQueue lineQueue = new LinkedBlockingQueue();
private boolean last_line_through_exception = false;
public boolean ProcessLine(String l, boolean background) {
try {
if (!current_ifstate
&& !l.startsWith("else")
&& !l.startsWith("fi")) {
return true;
}
if (l.endsWith("&")) {
background = true;
l = l.substring(0, l.length() - 1);
}
int vsindex = -1;
int veindex = -1;
while (((vsindex = l.indexOf("${")) >= 0)
&& ((veindex = l.indexOf("}", vsindex + 2)) > vsindex)) {
String var = l.substring(vsindex + 2, veindex);
//System.out.println("var = " + var);
String val = getval(var);
//System.out.println("val = " + val);
l = l.substring(0, vsindex) + val + l.substring(veindex + 1);
}
if (l.length() < 1) {
return true;
}
String largs[] = this.splitArgs(l);
if (largs[0].endsWith(".pvjscript")) {
File f0 = this.strToFile(largs[0]);
if (!f0.exists()) {
System.err.println(f0.getCanonicalPath() + " does not exist.");
return false;
}
for (int i = 0; i < largs.length; i++) {
this.addTmpVar(Integer.toString(i), largs[i]);
}
this.addTmpVar("*", this.arrayToStr(Arrays.copyOfRange(largs, 1, largs.length)));
this.RunScriptFile(f0);
return true;
}
if (largs[0].compareTo("then") == 0
|| largs[0].compareTo("do") == 0) {
if (l.length() < 6) {
return true;
}
l = l.substring(5);
if (l.length() < 1) {
return true;
}
largs = this.splitArgs(l);
}
for (int i = 0; i < largs.length; i++) {
if (largs[i].startsWith("$")) {
String aftervar = largs[i].substring(1);
String var = "";
while (aftervar.length() > 0
&& Character.isJavaIdentifierPart(aftervar.charAt(0))) {
var += aftervar.substring(0, 1);
aftervar = aftervar.substring(1);
}
largs[i] = getval(var) + aftervar;
} else if (largs[i].startsWith("2>/dev/null")) {
largs[i] = "";
}
}
for (int i = 0; i < largs.length; i++) {
while (((vsindex = largs[i].indexOf('`')) >= 0)
&& ((veindex = largs[i].indexOf('`', vsindex + 2)) > vsindex)) {
String var = largs[i].substring(vsindex + 1, veindex);
String val = RunCmd(var);
appendDebug("+`" + var + "` produced " + val);
largs[i] = largs[i].substring(0, vsindex) + val + largs[i].substring(veindex + 1);
}
}
largs = this.expandFileGlobs(largs);
if (null == scriptPv) {
this.setDir(new File(System.getProperty("user.dir")));
this.initEnvp();
scriptPv = this.createPv(l);
CurrentPv = this.scriptPv;
}
this.appendDebug("orig=" + l);
switch (checkBuiltIns(largs)) {
case 0:
appendDebug("+" + l, this.scriptPv.getBuiltinStyle());
if (null != builtin_output && builtin_output.length() > 0) {
scriptPv.appendOut(builtin_output);
builtin_output = "";
}
return true;
case 1:
appendDebug("+" + l, this.scriptPv.getBuiltinStyle());
if (null != builtin_output && builtin_output.length() > 0) {
scriptPv.appendOut(builtin_output);
builtin_output = "";
}
return false;
}
this.last_line_through_exception = false;
if (null != builtin_output && builtin_output.length() > 0) {
scriptPv.appendOut(builtin_output);
builtin_output = "";
}
if (background) {
ProcessView pv = this.createPv(this.arrayToStr(largs));
pv.Start(scriptPv);
this.addJob(pv);
} else {
scriptPv.setCommand(this.arrayToStr(largs));
scriptPv.Start(scriptPv);
scriptPv.waitFor();
}
return true;
} catch (Exception exception) {
this.last_line_through_exception = true;
exception.printStackTrace();
if(JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(this,"Continue after error :" +exception.getMessage() +"?")) {
return true;
}
}
return false;
}
private void addTmpVar(String var, String val) {
if (null == var || null == val) {
return;
}
var = var.trim();
if (var.length() < 1) {
System.err.println("empty var name.");
return;
}
val = val.trim();
if (null == tmpVars) {
tmpVars = new HashMap();
}
tmpVars.put(var, val);
this.appendDebug("addTmpVar( "+var+","+val+")");
}
private void addEnvVar(String var, String val) {
if (null == var || null == val) {
return;
}
var = var.trim();
if (var.length() < 1) {
System.err.println("empty var name.");
return;
}
val = val.trim();
if (null == envp) {
envp = new String[1];
} else {
for (int i = 0; i < envp.length; i++) {
if (envp[i].startsWith(var + "=")) {
envp[i] = var + "=" + val;
return;
}
}
String[] old_envp = envp;
envp = new String[envp.length + 1];
System.arraycopy(old_envp, 0, envp, 0, old_envp.length);
}
envp[envp.length - 1] = var + "=" + val;
this.setEnvp(envp);
}
private String find_rcslib_dir() {
String rcslib_dir = "";
try {
File rcslib_dir_f = null;
if (rcslib_dir != null && rcslib_dir.length() > 0) {
rcslib_dir_f = this.strToFile(rcslib_dir);
}
if (null == rcslib_dir_f
|| !rcslib_dir_f.exists()
|| !rcslib_dir_f.isDirectory()) {
File store_file =
new File(System.getProperty("user.dir"), ".rcslib_dir.txt");
if (store_file.exists()) {
BufferedReader br = new BufferedReader(new FileReader(store_file));
String possible_rcslib_dir = br.readLine().trim();
File pf = new File(possible_rcslib_dir);
if (pf.exists() && pf.isAbsolute() && pf.isDirectory()) {
rcslib_dir = pf.getAbsolutePath();
return rcslib_dir;
}
br.close();
}
String cp = System.getProperty("java.class.path");
if (null != cp) {
String dirs[] = cp.split(File.pathSeparator);
String match_s = File.separator + "rcslib" + File.separator;
for (int i = 0; i < dirs.length; i++) {
int dir_index = dirs[i].indexOf(match_s);
if (dir_index > 0) {
String possible_rcslib_dir = dirs[i].substring(0, dir_index + match_s.length());
File pf = new File(possible_rcslib_dir);
if (pf.exists() && pf.isAbsolute() && pf.isDirectory()) {
rcslib_dir = pf.getAbsolutePath();
}
}
}
}
rcslib_dir = JOptionPane.showInputDialog("RCS Library Directory?", rcslib_dir);
if (null == rcslib_dir) {
return "";
}
rcslib_dir_f = this.strToFile(rcslib_dir);
if (rcslib_dir_f.exists() && rcslib_dir_f.isDirectory()) {
rcslib_dir = rcslib_dir_f.getAbsolutePath();
}
this.addEnvVar("RCSLIB_DIR", rcslib_dir);
PrintStream ps = new PrintStream(new FileOutputStream(store_file));
ps.println(rcslib_dir);
ps.close();
}
} catch (Exception exception) {
exception.printStackTrace();
}
return rcslib_dir;
}
private String query_val(String var) {
String val = "";
try {
File rcslib_dir_f = null;
if (val != null && val.length() > 0) {
rcslib_dir_f = this.strToFile(val);
}
if (null == rcslib_dir_f
|| !rcslib_dir_f.exists()
|| !rcslib_dir_f.isDirectory()) {
File store_file =
new File(System.getProperty("user.dir"), "." + var + ".txt");
if (store_file.exists()) {
BufferedReader br = new BufferedReader(new FileReader(store_file));
val = br.readLine().trim();
br.close();
}
val = JOptionPane.showInputDialog(var + " ?", val);
if (null == val) {
return "";
}
this.addEnvVar(var, val);
PrintStream ps = new PrintStream(new FileOutputStream(store_file));
ps.println(val);
ps.close();
}
} catch (Exception exception) {
exception.printStackTrace();
}
return val;
}
private void initEnvp() {
Map map = System.getenv();
for (String var : map.keySet()) {
this.addEnvVar(var, System.getenv(var));
}
Properties p = System.getProperties();
for (String var : p.stringPropertyNames()) {
this.addEnvVar(var, p.getProperty(var));
}
}
private int script_line_num = 0;
private String script_name = "";
public void appendErr(String s) {
s = script_name + ":" + script_line_num + " " + s;
if (null != scriptPv) {
scriptPv.appendErr(s);
} else {
System.err.println(s);
}
}
public void appendDebug(String s, Style style) {
s = script_name + ":" + script_line_num + " " + s;
if (null != scriptPv) {
scriptPv.appendDebug(s, style);
}
}
public void appendDebug(String s) {
s = script_name + ":" + script_line_num + " " + s;
if (null != scriptPv) {
if (this.last_cmd_was_builtin) {
scriptPv.appendDebug(s, scriptPv.getBuiltinStyle());
} else {
scriptPv.appendDebug(s, scriptPv.getExternalStyle());
}
}
}
public void appendOutPlusErr(String s, Style style) {
s = script_name + ":" + script_line_num + " " + s;
if (null != scriptPv) {
scriptPv.appendOutPlusErr(s, style);
} else {
System.err.println(s);
}
}
BufferedReader script_reader = null;
File script_file = null;
long script_bytes_read = 0;
public void RunScriptFile(File f) {
try {
val0 = f.getCanonicalPath();
String user_dir = System.getProperty("user.dir");
this.setTitle(f.toString() + " : " + user_dir);
this.setDir(new File(user_dir));
initEnvp();
script_file = f;
script_reader = new BufferedReader(new FileReader(script_file));
script_name = f.getName();
scriptPv = this.createPv(f.getName());
script_line_num = 1;
addJob(scriptPv);
this.CurrentPv = scriptPv;
String l;
while ((l = script_reader.readLine()) != null) {
script_bytes_read += l.length() + 1;
script_line_num++;
boolean background = false;
String next_l = null;
while (l.endsWith("\\")
&& (next_l = script_reader.readLine()) != null) {
script_bytes_read += next_l.length() + 1;
script_line_num++;
l = l.substring(0, l.length() - 1) + next_l;
}
if (l.startsWith("#")) {
continue;
}
String lines[] = l.split(";");
for (String lx : lines) {
lx = lx.trim();
if (lx.startsWith("#")) {
continue;
}
if (!this.ProcessLine(lx, background)) {
return;
}
}
}
script_reader.close();
script_reader = null;
} catch (Exception e) {
if (null != script_reader) {
try {
script_reader.close();
script_reader = null;
} catch (Exception e2) {
}
}
e.printStackTrace();
}
}
Thread mainThread = null;
public void startMainThread() {
if (mainThread != null) {
mainThread.interrupt();
}
mainThread = new Thread(new Runnable() {
public void run() {
try {
while (!Thread.interrupted()) {
String l = lineQueue.take();
ProcessLine(l, false);
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
});
mainThread.start();
}
public void Run(final String args[]) {
this.startMainThread();
int starting_arg = 0;
for (starting_arg = 0; starting_arg < args.length; starting_arg++) {
if (!args[0].startsWith("-")) {
break;
}
if (args[0].compareTo("--debug") == 0
|| args[0].compareTo("-d") == 0) {
this.vw_state = ViewState.ViewStdOutAndStdErrAndDebug;
}
}
if (System.getenv("DEBUG") != null) {
this.vw_state = ViewState.ViewStdOutAndStdErrAndDebug;
}
lineQueue.add(arrayToStr(args, starting_arg));
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
final String fargs[] = args;
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
Main pvjf = new Main();
pvjf.setVisible(true);
pvjf.Run(fargs);
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.ButtonGroup buttonGroupVw;
private javax.swing.JCheckBoxMenuItem jCheckBoxMenuItemAutoScroll;
private javax.swing.JDialog jDialogEnvp;
private javax.swing.JMenu jMenu1;
private javax.swing.JMenu jMenu2;
private javax.swing.JMenuBar jMenuBar1;
private javax.swing.JMenuItem jMenuItem1;
private javax.swing.JMenuItem jMenuItem2;
private javax.swing.JMenuItem jMenuItemOpen;
private javax.swing.JMenuItem jMenuItemSetScrollLimit;
private javax.swing.JMenu jMenuOptions;
private javax.swing.JMenu jMenuProcess;
private javax.swing.JMenu jMenuTools;
private javax.swing.JRadioButtonMenuItem jRadioButtonMenuItemViewBoth;
private javax.swing.JRadioButtonMenuItem jRadioButtonMenuItemViewDebug;
private javax.swing.JRadioButtonMenuItem jRadioButtonMenuItemViewStdErr;
private javax.swing.JRadioButtonMenuItem jRadioButtonMenuItemViewStdOut;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPaneEnvpTable;
private javax.swing.JTable jTableEnvp;
private javax.swing.JTextField jTextFieldCmd;
private javax.swing.JTextPane jTextPane1;
// End of variables declaration//GEN-END:variables
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy