How to move files and folders to Trash programmatically on macOS? - objective-c

All I can find on this topic is mentions of FSMoveObjectToTrashSync function, which is now deprecated and no alternative is listed for it.
How to do it from C or Objective-C code?

Use NSFileManager:
https://developer.apple.com/documentation/foundation/nsfilemanager
trashItemAtURL:resultingItemURL:error:
Moves an item to the trash.

In C, you can use AppleScript to move files to the trash. Here's a simple example:
#include <stdio.h>
#include <stdlib.h>
#define PATH "/tmp/"
#define NAME "delete-me.txt"
int main() {
int status;
/* Create a file */
FILE *f;
f = fopen(PATH NAME, "w");
if (!f) {
fputs("Can't create file " PATH NAME "\n", stderr);
return 1;
}
fputs("I love trash\n", f);
fclose(f);
/* Now put it in the trash */
status = system(
"osascript -e 'set theFile to POSIX file \"" PATH NAME "\"' "
"-e 'tell application \"Finder\"' "
"-e 'delete theFile' "
"-e 'end tell' "
">/dev/null"
);
if (status == 0) {
puts("Look in the trash folder for a file called " NAME);
}
else {
puts("Something went wrong. Unable to delete " PATH NAME);
}
return 0;
}
A few notes:
Multi-line scripts have to be sent as multiple -e command line options.
Since osascript insists on printing status messages to the command line console, I've redirected its output to /dev/null. But, if a file of the same name already exists in the trash, then the deleted file will be renamed. If you need to know this name, you'll have to use popen() instead of system() and parse the return string from osascript.

Related

How to update a variable from inside an AWK function

I run this script from a loop inside another script and I want to:
a) print errors into a file keeping track of number of line, name of file and error.
b)I want to print into another file the unique names of files in which an error has been found, provided that a single file could have more than one error and I don't like repetitions.
I know I can sort | unique the file in the end from the calling script but... Is there another technique?
Something like:
if(tempVar != FILENAME)
{
print FILENAME >> uniqueFiles;
}
tempVar= FILENAME;
here's my script
awk '
function errorHandler(error1)
{
print FILENAME >> uniqueFiles;
print FILENAME";"NR";"error >> errorListing;
uniqueFiles = FILENAME;
}
BEGIN {
uniqueFiles="files.txt";
errorListing="errorList.txt";
error1="Error code 1"
}
{
if(NR>1)
{
if(length($1) != 10)
{
errorHandler(error1);
}
}
}
END{}' $1

How to code "git commit" in libgit2?

I have searched Google and Stackoverflow for an answer to the question of how to code the equivalent of
git commit -a -m "message"
in libgit2 (https://libgit2.github.com) and C or C++.
But I cannot find a ready and working answer to this question.
I am using libgit2-0.21.
Below is code that initializes a git repository, adds two files to it, and stages the two files so they are ready to be committed.
My question is how to code "git commit -a -m "msg" in libgit2?
#include <sys/stat.h>
#include <string>
#include <fstream>
#include <iostream>
#include <git2.h>
using namespace std;
int main (int argc, char** argv)
{
git_threads_init ();
// Create repository directory.
string directory = "repository";
mkdir (directory.c_str(), 0777);
// Initialize the repository: git init.
git_repository *repo = NULL;
int result = git_repository_init (&repo, directory.c_str(), false);
if (result != 0) cerr << giterr_last ()->message << endl;
// Store two files in the repository directory.
ofstream file;
file.open ("repository/file1", ios::binary | ios::trunc);
file << "Contents of file one";
file.close ();
file.open ("repository/file2", ios::binary | ios::trunc);
file << "Contents of file two";
file.close ();
// Run the equivalent of "git add ."
// Get the git index.
git_index * index = NULL;
result = git_repository_index (&index, repo);
if (result != 0) cerr << giterr_last ()->message << endl;
// Add all files to the git index.
result = git_index_add_all (index, NULL, 0, NULL, NULL);
if (result != 0) cerr << giterr_last ()->message << endl;
// Write the index to disk.
result = git_index_write (index);
if (result != 0) cerr << giterr_last ()->message << endl;
// Run the equivalent of "git commit -a -m "commit message".
// How to do that through libgit2?
// Run "git status" to see the result.
system ("cd repository; git status");
// Free resources.
git_index_free (index);
git_repository_free (repo);
git_threads_shutdown ();
return 0;
}
The code can be compiled as follows:
g++ -Wall -I/opt/local/include -L/opt/local/lib -lgit2 -o test git.cpp
Below is the output of running the compiled binary:
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file1
new file: file2
Once the index is updated
create a tree from it through git_index_write_tree()
create a commit that references this tree through git_commit_create_v()
See this end to end test which performs the equivalent of the following
$ echo "test" > test.txt
$ git add .
$ git commit -m "Initial commit"

Bison/Flex Parsing File

I have recently tried using GNU Bison and Flex to write a interpreter. The text I want the interpreter to recognize is print "Hello" and I have tried the following:
flex file:
%{
#include <iostream>
using namespace std;
#define YY_DECL extern "C" int yylex()
#include "gbison.tab.h"
%}
%%
[ \t\n] ;
'\"' return QUOTE;
[a-zA-Z0-9]+ { yylval.sval = strdup(yytext); return STRING; }
%%
bison file:
%{
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
extern "C" int yylex();
extern "C" int yyparse();
extern "C" FILE* yyin;
void yyerror (const char* s);
%}
%union {
char* sval;
}
%token <sval> STRING
%token QUOTE
%%
str:
STRING QUOTE STRING QUOTE
{
if (strcmp($1, "print") == 0)
{
cout << $3 << flush;
}
if (strcmp($1, "println") == 0)
{
cout << $3 << endl;
}
}
;
%%
main(int argc, char* argv[])
{
FILE* input = fopen(argv[1], "r");
if (!input)
{
cout << "Bad input. Nonexistant file" << endl;
return -1;
}
yyin = input;
do
{
yyparse();
} while (!feof(yyin));
}
void yyerror(const char* s)
{
cout << "Error. " << s << endl;
exit(-1);
}
But when I pass print "hello" to the compiled program I get:
"Error. syntax error
I think that the issue is the STRING QUOTE STRING QUOTE but I am not sure. What is exactly is going wrong? How would I get the interpreter to print hello?
The answers are below, but I hope the following is more generally useful, as fishing instruction.
There are a variety of debugging tools which would help you. In particular, flex provides the -d flag:
-d, --debug
makes the generated scanner run in "debug" mode. Whenever a pattern is recognized and the global variable yy_flex_debug is non-zero (which is the default), the scanner will write to stderr a line… (flex manual)
bison also provides a debug facility. (bison manual)
There are several means to enable compilation of trace facilities:
the macro YYDEBUG…
the option -t (POSIX Yacc compliant)…
the option --debug (Bison extension)…
the directive %debug…
We suggest that you always enable the debug option so that debugging
is always possible.
…
Once you have compiled the program with trace facilities, the way to
request a trace is to store a nonzero value in the variable yydebug.
You can do this by making the C code do it (in main, perhaps), or you
can alter the value with a C debugger.
Also, remember that flex inserts an automatic rule which causes any otherwise unrecognized character to be echoed to the output. ("By default, any text not matched by a flex scanner is copied to the output" -- Some simple examples) That's why you have the extra " in the error message being printed by your program:
"Error. syntax error
^
That's a bit subtle, though. Tracing flex would have shown you that more directly.
So, finally, the problem(s):
The flex pattern '\"' does not match a ". It matches '"', because single quotes are not special to flex. That's definitely why your parse fails.
Fixing that will let your program parse a single command, but it will generate a syntax error if you try to give it two print commands in the same input. That's because bison always parses until it receives an END token from the lexer, and the lexer (by default) only provides an END token when it reaches the end of the input. You can change
the lexer behaviour (by sending END in other circumstances, for example a new-line) (not recommended)
the parser behaviour (by using ACCEPT) (possible, but rarely necessary)
the grammar, so that it recognizes any number of statements. (recommended)

Use awk to tarball specified files

I have the following output from repo status:
project X/Y (*** NO BRANCH ***)
-- A/B/c
-m D/E/f
project Z/ (*** NO BRANCH ***)
-- G/H/i
-m J/K/l
(lowercase letters are files, and uppercase are dirs)
The lines prefixed with -- indicate newly added files. repo diff does not include these files, so I can't create a patch that includes all differences. So, I'll just create tarball of them.
Q: What script (e.g., awk, perl, or python) can I use to create a tarball of these files? The tarball should contain:
X/Y/A/B/c
Z/G/H/i
I'm thinking an awk script would be something like this (I'm not that familiar w/syntax):
awk {
BEGIN curdir = '', filelist = []
{
if ($0 == "project") {
curdir = $1
} else if ($0 == "--") {
# insert file specified by $1 into tarball
}
}
}
Ideas? Thanks!
You are close. Here is some suggestion:
/^project/ {
dir = $2
}
$1 == "--" {
fullpath = dir $2 # space between dir and $2 means concatenation
print fullpath
# Do something with fullpath such as
# system("tar ...")
}
Discussion
$1 is the first field (token) in a line, $2 is the second field, and so on
$0 represent the whole record (line)
Every time we see a line that starts with project, we save the directory, $2 to the variable dir
Every time we see the first field of "--", we print out the directory, concatenated with the file name. In your case, insert command to archive the file here.

how to parse from command line arguements in yacc?

how to parse from command line arguements in yacc ?
of course i undefined input in both lex & yacc and then wrote
int input(void)
{
printf("in input\n:");
char c;
if(target > limit)
return 0;
if((c = target[0][offset++]) != '\0')
return (c);
target++;
offset =0;
return (' ');
}
where target contains the command line arguements. But only the standard input is getting excueted how to make dis input function get executed.
Did you mean you want your generates parser accept command line arguments? Then you need to add those arguments to the main function. The lexer input is called FILE* yyin, and is initialized to stdin in the lexer. You can change the default behavior by
#include <stdio.h>
extern FILE* yyin;
int main(int argv, char** argv)
{
if(argc==2)
{
yyin = fopen(argv[1], "r");
if(!yyin)
{
fprintf(stderr, "can't read file %s\n", argv[1]);
return 1;
}
}
yyparse();
}
If you want your own function to be executed instead of the one provided by flex, you need to define the YY_INPUT macro.