vala FileInfo get_file_type is UNKNOWN - glib

I've been trying to make a function that goes through a directory and lists all the files in the directory and any sub-directories:
void get_listing (string dir) {
try {
var directory = File.new_for_path (dir);
var enumerator = directory.enumerate_children (FILE_ATTRIBUTE_STANDARD_NAME, 0);
FileInfo file_info;
while ((file_info = enumerator.next_file ()) != null) {
stdout.printf(file_info.get_file_type().to_string());
if (file_info.get_file_type() == FileType.DIRECTORY) {
get_listing(file_info.get_name());
} else {
stdout.printf ("%s\n", file_info.get_name ());
}
}
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
return;
}
}
int main (string[] args) {
get_listing(".");
return 0;
}
When I run this code none of the files in any sub-directories are outputted. All the files/directories types are "G_FILE_TYPE_UNKNOWN". Does anyone know how to fix this or another method I could use.

You are enumerating files by name only; if you wish to access file type later, you should pass appropriate hint to enumerator:
FILE_ATTRIBUTE_STANDARD_NAME + "," + FILE_ATTRIBUTE_STANDARD_TYPE

Related

Listen to a background process in vala

I have a command I want to listen to in the background Process.spawn_command_line_async is what I want but I can't work out how to then listen to the response. The command will output lines when something needs updating and I then need to parse that line and run a function accordingly. The process won't end until stopped, so will need to be listened to as it's running.
What you want is Process.spawn_commandline_async_with_pipes (). Valadoc has a code example:
private static bool process_line (IOChannel channel, IOCondition condition, string stream_name) {
if (condition == IOCondition.HUP) {
print ("%s: The fd has been closed.\n", stream_name);
return false;
}
try {
string line;
channel.read_line (out line, null, null);
print ("%s: %s", stream_name, line);
} catch (IOChannelError e) {
print ("%s: IOChannelError: %s\n", stream_name, e.message);
return false;
} catch (ConvertError e) {
print ("%s: ConvertError: %s\n", stream_name, e.message);
return false;
}
return true;
}
public static int main (string[] args) {
MainLoop loop = new MainLoop ();
try {
string[] spawn_args = {"ls", "-l", "-h"};
string[] spawn_env = Environ.get ();
Pid child_pid;
int standard_input;
int standard_output;
int standard_error;
Process.spawn_async_with_pipes ("/",
spawn_args,
spawn_env,
SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
null,
out child_pid,
out standard_input,
out standard_output,
out standard_error);
// stdout:
IOChannel output = new IOChannel.unix_new (standard_output);
output.add_watch (IOCondition.IN | IOCondition.HUP, (channel, condition) => {
return process_line (channel, condition, "stdout");
});
// stderr:
IOChannel error = new IOChannel.unix_new (standard_error);
error.add_watch (IOCondition.IN | IOCondition.HUP, (channel, condition) => {
return process_line (channel, condition, "stderr");
});
ChildWatch.add (child_pid, (pid, status) => {
// Triggered when the child indicated by child_pid exits
Process.close_pid (pid);
loop.quit ();
});
loop.run ();
} catch (SpawnError e) {
print ("Error: %s\n", e.message);
}
return 0;
}
valac --pkg glib-2.0 GLib.Process.spawn_async_with_pipes.vala

Vala get file modification date

I'm new to Vala and linux programming in general.
Im am trying to enumerate the data similar to the 'stat' shell utility for a given folder.
So far it's this i got:
int main (string[] args) {
try {
File directory = File.new_for_path (".");
if (args.length > 1) {
directory = File.new_for_commandline_arg (args[1]);
}
FileEnumerator enumerator = directory.enumerate_children (FileAttribute.TIME_MODIFIED, 0);
FileInfo file_info;
while ((file_info = enumerator.next_file ()) != null) {
DateTime t = file_info.get_modification_date_time();
}
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
return 1;
}
return 0;
}
Console output:
vala --pkg gio-2.0 --pkg glib-2.0 main3.vala
main3.vala:16.24-16.59: error: The name `get_modification_date_time' does not exist in the context of `GLib.FileInfo?'
Could someone point me in the right direction?
Thanks.
The error is saying the method doesn't exist. Looking at Valadoc.org for get_modification_date_time it shows this was introduced in GLib version 2.62. That version was released 05 September 2019. It is likely your distribution doesn't include that release yet.
You can either try to update your version of GLib or use the now deprecated get_modification_time:
int main(string[] args) {
if (args[1] == null) {
stderr.printf("No filename given\n");
return 1;
}
var file = GLib.File.new_for_path (args[1]);
try {
GLib.FileInfo info = file.query_info("*", FileQueryInfoFlags.NONE);
print (info.get_modification_time().to_iso8601() + "\n");
print ("\n\nFull info:\n");
foreach (var item in info.list_attributes (null)) {
print( #"$item - $(info.get_attribute_as_string (item))\n" );
}
} catch (Error error) {
stderr.printf (#"$(error.message)\n");
return 1;
}
return 0;
}

Is there any way to extract text from .tex file?

I am writing a program to count words in a file. I am facing problems while parsing .tex files.
This code need to go on a website where it has to count words from the file that is being uploaded. I have managed to do it but I am looing for some better solutions
case "application/x-tex": // Avoid words with '\' and count
Scanner sc1;
try {
sc1 = new Scanner(new URL(URLPath).openStream());
while (sc1.hasNext()) {
String str = sc1.next();
if (!str.contains("\\")) {
System.out.print(str + " ");
wordCount++;
}
}
sc1.close();
} catch (IOException e) {
System.out.println("There was a problem while reading File on the URL");
break;
// e.printStackTrace();
}
if (wordCount <= 0) {
System.out.println("Total count is " + wordCount
+ ". The uploaded File is either empty or it consists of Images only");
} else {
System.out.println("");
System.out.println("**********");
System.out.println("Word Count: " + wordCount);
System.out.println("**********");
System.out.println("");
}
break;
I am expecting a String output which I could further use to count words.
// Trigger perl script
URL website = new URL(URLPath);
Path path = Paths.get("myfile.tex");
bufferFiles.add(new File("myFile.tex"));
try (InputStream in = website.openStream()) {
Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING);
}
URL texcount = new URL("https://papertrue.s3.us-west-1.amazonaws.com/draft/77e3c992-b70f-4711-8b9b-eaf390617bb8");
Path path1 = Paths.get("texcount.pl");
bufferFiles.add(new File("texcount.pl"));
try (InputStream in = texcount.openStream()) {
Files.copy(in, path1, StandardCopyOption.REPLACE_EXISTING);
}
wordCount = 0;
Process process;
try {
process = Runtime.getRuntime().exec("/etc/papertrue/texcount.pl myfile.tex");
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
String tem[] = line.split(":\\s");
log.debug(tem[tem.length - 1]);
try {
wordCount += Integer.parseInt(tem[tem.length - 1]);
} catch (Exception e) {
}
}
process.waitFor();
if (process.exitValue() == 0) {
log.debug("Command Successful");
} else {
log.debug("Command Failure");
}
log.debug(wordCount);
} catch (IOException e) {
log.debug("There was a problem while reading File on the URL");
e.printStackTrace();
break;
}

Writing a list of strings to a file

From the API page, I gather there's no function for what I'm trying to do. I want to read text from a file storing it as a list of strings, manipulate the text, and save the file. The first part is easy using the function:
abstract List<String> readAsLinesSync([Encoding encoding = Encoding.UTF_8])
However, there is no function that let's me write the contents of the list directly to the file e.g.
abstract void writeAsLinesSync(List<String> contents, [Encoding encoding = Encoding.UTF_8, FileMode mode = FileMode.WRITE])
Instead, I've been using:
abstract void writeAsStringSync(String contents, [Encoding encoding = Encoding.UTF_8, FileMode mode = FileMode.WRITE])
by reducing the list to a single string. I'm sure I could also use a for loop and feed to a stream line by line. I was wondering two things:
Is there a way to just hand the file a list of strings for writing?
Why is there a readAsLinesSync but no writeAsLinesSync? Is this an oversight or a design decision?
Thanks
I just made my own export class that handles writes to a file or for sending the data to a websocket.
Usage:
exportToWeb(mapOrList, 'local', 8080);
exportToFile(mapOrList, 'local/data/data.txt');
Class:
//Save data to a file.
void exportToFile(var data, String filename) =>
new _Export(data).toFile(filename);
//Send data to a websocket.
void exportToWeb(var data, String host, int port) =>
new _Export(data).toWeb(host, port);
class _Export {
HashMap mapData;
List listData;
bool isMap = false;
bool isComplex = false;
_Export(var data) {
// Check is input is List of Map data structure.
if (data.runtimeType == HashMap) {
isMap = true;
mapData = data;
} else if (data.runtimeType == List) {
listData = data;
if (data.every((element) => element is Complex)) {
isComplex = true;
}
} else {
throw new ArgumentError("input data is not valid.");
}
}
// Save to a file using an IOSink. Handles Map, List and List<Complex>.
void toFile(String filename) {
List<String> tokens = filename.split(new RegExp(r'\.(?=[^.]+$)'));
if (tokens.length == 1) tokens.add('txt');
if (isMap) {
mapData.forEach((k, v) {
File fileHandle = new File('${tokens[0]}_k$k.${tokens[1]}');
IOSink dataFile = fileHandle.openWrite();
for (var i = 0; i < mapData[k].length; i++) {
dataFile.write('${mapData[k][i].real}\t'
'${mapData[k][i].imag}\n');
}
dataFile.close();
});
} else {
File fileHandle = new File('${tokens[0]}_data.${tokens[1]}');
IOSink dataFile = fileHandle.openWrite();
if (isComplex) {
for (var i = 0; i < listData.length; i++) {
listData[i] = listData[i].cround2;
dataFile.write("${listData[i].real}\t${listData[i].imag}\n");
}
} else {
for (var i = 0; i < listData.length; i++) {
dataFile.write('${listData[i]}\n');
}
}
dataFile.close();
}
}
// Set up a websocket to send data to a client.
void toWeb(String host, int port) {
//connect with ws://localhost:8080/ws
//for echo - http://www.websocket.org/echo.html
if (host == 'local') host = '127.0.0.1';
HttpServer.bind(host, port).then((server) {
server.transform(new WebSocketTransformer()).listen((WebSocket webSocket) {
webSocket.listen((message) {
var msg = json.parse(message);
print("Received the following message: \n"
"${msg["request"]}\n${msg["date"]}");
if (isMap) {
webSocket.send(json.stringify(mapData));
} else {
if (isComplex) {
List real = new List(listData.length);
List imag = new List(listData.length);
for (var i = 0; i < listData.length; i++) {
listData[i] = listData[i].cround2;
real[i] = listData[i].real;
imag[i] = listData[i].imag;
}
webSocket.send(json.stringify({"real": real, "imag": imag}));
} else {
webSocket.send(json.stringify({"real": listData, "imag": null}));
}
}
},
onDone: () {
print('Connection closed by client: Status - ${webSocket.closeCode}'
' : Reason - ${webSocket.closeReason}');
server.close();
});
});
});
}
}
I asked Mads Agers about this. He works on the io module. He said that he decided not to add writeAsLines because he didn't find it useful. For one it is trivial to write the for loop and the other thing is that you have to parameterize it which the kind of line separator that you want to use. He said he can add it if there is a strong feeling that it would be valuable. He didn't immediately see a lot of value in it.

DTE2 _applicationObject reading filename in folder

below is the current codes i have.
what it does is basically loop thru project solution project file and detect if it is a C# file. however it can't detect files that are put in a folder , how can i modify it to read a C# file in a solution folder.
Regards , Andy
foreach (var projectItem in
_applicationObject.Solution.Projects.Cast<Project>().SelectMany(project => project.ProjectItems.Cast<ProjectItem>()))
{
//for (var i = 0; i < projectItem.FileCount; i++)
//{
if (projectItem.FileCount > 0 && projectItem.Name.EndsWith(".cs")) // check if project is .Cs files
{
string fileName;
try
{
fileName = projectItem.FileNames[0];
}
catch (Exception)
{
continue;
}
//end of find filename
}
}
This will print all items in the solution, I believe.
It works with C++ solution in VS 2012.
// XXX Test
IEnumerator enumerator = m_applicationObject.Solution.GetEnumerator();
string indent = " ";
while (enumerator.MoveNext())
{
Project p = enumerator.Current as Project;
if (p != null)
{
Debug.WriteLine(p.Name);
ProcessProjectItems(p.ProjectItems, indent);
}
}
// XXX Test
void ProcessProjectItems(ProjectItems pis, string indent)
{
if (pis == null)
return;
IEnumerator items = pis.GetEnumerator();
while (items.MoveNext())
{
ProjectItem pi = items.Current as ProjectItem;
if (pi != null)
{
Debug.WriteLine(indent + pi.Name);
if (pi.ProjectItems != null)
{
ProcessProjectItems(pi.ProjectItems, indent + " ");
}
else
{
Project p = pi.Object as Project;
if (p != null && p.ProjectItems != null)
ProcessProjectItems(p.ProjectItems, indent + " ");
}
}
}
}

Resources