Bash 4 had parameter expansion operations which allowed to convert string stored in variable to upper/lower case using ${v^}, ${v^^}, ${v,}, or ${v,,}. In Bash 5 new # notation was added to provide various expansion operations, some of which also include case conversions: ${v^} == ${v#u}, ${v^^} == ${v#U}, ${v,,} == ${v#L} (no matching operator for ${v,} it seems).
What is the difference between ${v^^} and ${v#U}, and for what purpose new operators that do the same thing were added?
Expansions like ${x^^} take an optional pattern (that should match a single character at a time; it defaults to ? if omitted) that controls which characters are upper cased, while ${x#U} upper cases all characters. If you leave out the pattern in the first form they're equivalent, but if you specify one they're not the same. ${x^^[aeiou]} will only uppercase vowels, for example.
It seems that the code eventually end in the same function sh_modcase.
^^ and the family is expanded in parameter_brace_casemod, while the newer syntax is expanded in string_transform.
Looking at string_transform it's evident that other transformations are also possible:
switch (xc)
{
/* Transformations that interrogate the variable */
case 'a':
i = var_attribute_string (v, 0, flags);
ret = (i > 0) ? savestring (flags) : (char *)NULL;
break;
case 'A':
ret = string_var_assignment (v, s);
break;
case 'K':
ret = sh_quote_reusable (s, 0);
break;
/* Transformations that modify the variable's value */
case 'E':
t = ansiexpand (s, 0, strlen (s), (int *)0);
ret = dequote_escapes (t);
free (t);
break;
case 'P':
ret = decode_prompt_string (s);
break;
case 'Q':
ret = sh_quote_reusable (s, 0);
break;
case 'U':
ret = sh_modcase (s, 0, CASE_UPPER);
break;
case 'u':
ret = sh_modcase (s, 0, CASE_UPFIRST); /* capitalize */
break;
case 'L':
ret = sh_modcase (s, 0, CASE_LOWER);
break;
default:
ret = (char *)NULL;
break;
}
My program accepts many options.
And I have to write a shell script to test my program.
The shell script must run my program multiple times and every time it must pass different options and different arguments for an option.
For example:
#!/bin/bash
echo "CS111 " > testing.txt
echo "is " >> testing.txt
echo "intersting " >> testing.txt
echo "even " >> testing.txt
echo "though " >> testing.txt
echo "it " >> testing.txt
echo "is " >> testing.txt
echo "time " >> testing.txt
echo "consuming " >> testting.txt
echo "and " >> testing.txt
echo "hard " >> testing.txt
./simpsh \
--verbose \
--rdonly in.txt \
--append --wronly out.txt \
--wronly err.txt \
--command 0 1 2 sort testing
./simpsh \
--verbose\
--rdonly in.txt \
--append --wronly out.txt \
--wronly err.txt \
--command 0 1 2 sort
The first test will be executed, but then there is an error 127.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
int main(int argc, char **argv)
{
int c;
int oflag = 0;
int *fd;
int fdCount = 0;
int pipefd[2];
int p;
int verbose = 0;
while (1) {
static struct option long_options[] = {
{"append",no_argument,0,'a'},
{"cloexec",no_argument,0,'b'},
{"creat", no_argument,0,'c'},
{"directory",no_argument,0,'d'},
{"dsync",no_argument,0,'e'},
{"excl",no_argument,0,'f'},
{"nofollow",no_argument,0,'g'},
{"nonblock",no_argument, 0,'h'},
{"rsync",no_argument,0,'i'},
{"sync",no_argument,0,'j'},
{"trunc",no_argument,0,'k'},
{"rdonly",required_argument,0,'l'},
{"rdwr",required_argument,0,'m'},
{"wronly",required_argument,0,'n'},
{"pipe",no_argument,0,'o'},
{"command",required_argument,0,'p'},
{"wait",no_argument,0,'q'},
{"close",required_argument,0,'r'},
{"verbose",no_argument,0,'s'},
{"profile",no_argument,0,'t'},
{"abort",no_argument,0,'u'},
{"catch",required_argument,0,'v'},
{"ignore",required_argument,0,'w'},
{"default",required_argument,0,'x'},
{"pause",no_argument,0,'y'},
};
c = getopt_long(argc, argv, "abcdefghijkl:m:n:op:qr:stuv:w:x:y", long_options, NULL);
if (c == -1)
break;
switch (c) {
case 'a':
if(verbose)
printf("O_APPEND\n");
oflag = oflag | O_APPEND;
break;
case 'b':
if(verbose)
printf("O_CLOEXEC\n");
oflag = oflag | O_CLOEXEC;
break;
case 'c':
if(verbose)
printf("O_CREAT\n");
oflag = oflag | O_CREAT;
break;
case 'd':
if(verbose)
printf("O_DIRECTORY\n");
oflag = oflag | O_DIRECTORY;
break;
case 'e':
if(verbose)
printf("O_DSYNC\n");
oflag = oflag | O_DSYNC;
break;
case 'f':
if(verbose)
printf("O_EXCL\n");
oflag = oflag | O_EXCL;
break;
case 'g':
if(verbose)
printf("O_NOFOLLOW\n");
oflag = oflag | O_NOFOLLOW;
break;
case 'h':
if(verbose)
printf("O_NONBLOCK\n");
oflag = oflag | O_NONBLOCK;
break;
case 'i':
if(verbose)
printf("O_RSYNC\n");
oflag = oflag | O_RSYNC;
break;
case 'j':
if(verbose)
printf("O_SYNC\n");
oflag = oflag | O_SYNC;
break;
case 'k':
if(verbose)
printf("O_TRUNC\n");
oflag = oflag | O_TRUNC;
break;
case 'l':
if(optarg){
if(fdCount == 0)
fd = (int *)malloc(sizeof(int));
else
fd = (int *)realloc(fd, (fdCount + 1)* sizeof(int));
if(verbose)
printf("O_RDONLY %s\n", optarg);
fd[fdCount] = open(optarg, oflag | O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
oflag = 0;
if(fd[fdCount] == -1){
fprintf(stderr, "%s cannot be opened/created", optarg);
exit(1);
}
else
fdCount++;
}
break;
case 'm':
if(optarg){
if(fdCount == 0)
fd = (int *)malloc(sizeof(int));
else
fd = (int *)realloc(fd, (fdCount + 1)* sizeof(int));
if(verbose)
printf("O_RDWR %s\n", optarg);
fd[fdCount] = open(optarg, oflag | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);
oflag = 0;
if(fd[fdCount] == -1){
fprintf(stderr, "%s cannot be opened/created", optarg);
exit(2);
}
else
fdCount++;
}
break;
case 'n':
if(optarg){
if(fdCount == 0)
fd = (int *)malloc(sizeof(int));
else
fd = (int *)realloc(fd, (fdCount + 1)* sizeof(int));
if(verbose)
printf("O_WRONLY %s\n", optarg);
fd[fdCount] = open(optarg, oflag | O_WRONLY, S_IRWXU | S_IRWXG | S_IRWXO);
oflag = 0;
if(fd[fdCount] == -1){
fprintf(stderr, "%s cannot be opened/created", optarg);
exit(3);
}
else
fdCount++;
}
break;
case 'o':
if(verbose)
printf("pipe\n");
p = pipe(pipefd);
if(p == -1){
fprintf(stderr, "The pipe wasn't made.\n");
exit(5);
}
else{
if(fdCount == 0)
fd = (int *)malloc(2 * sizeof(int));
else
fd = (int *)realloc(fd, (fdCount + 2) * sizeof(int));
fdCount = fdCount + 2;
fd[fdCount - 2] = pipefd[0];
fd[fdCount - 1] = pipefd[1];
}
break;
case 'p':
if(optarg){
if(verbose){
printf("command ");
int vi = optind -1;
for( vi = optind - 1; vi < argc && *argv[vi] != '-'; vi++)
printf("%s ", argv[vi]);
printf("\n");
}
pid_t pid = fork();
if(pid == 0){
int fdin;
int fdout;
int fderr;
int i = 0;
char **arg;
int index;
for(index = optind-1; index < argc && *argv[index] != '-'; index++, i++){
switch(i){
case 0:
fdin = atoi(argv[index]);
break;
case 1:
fdout = atoi(argv[index]);
break;
case 2:
fderr = atoi(argv[index]);
break;
default:
if(i - 3 == 0)
arg = (char**)malloc(sizeof(char));
else
arg = (char**)realloc(arg, ((i - 3) + 1)* sizeof(char));
arg[i - 3] = strdup(argv[index]);
}
}
dup2(fd[fdin],0);
close(fd[fdin]);
dup2(fd[fdout],1);
close(fd[fdout]);
dup2(fd[fderr],2);
close(fd[fderr]);
execvp(arg[0], arg);
}
else if(pid == -1){
fprintf(stderr, "The new proccess isn't created by fork()\n");
exit(6);
}
}
break;
case 'q':
break;
case 'r':
break;
case 's':
verbose = 1;
break;
case 't':
break;
case 'u':
break;
case 'v':
break;
case 'w':
break;
case 'x':
break;
case 'y':
break;
default:
fprintf(stderr, "An option is misstyped or has no argument\n");
exit(4);
}
}
exit(0);
}
Return code 127 indicates the command was not found.
It is likely myprogram is not found inside the current directory you execute your test script from.
Try changing to the directory where your program is located, or calling it with a full path.
Also, remember bash ignores commands that fail unless you activate the "-e" flag or trap errors and handle them explicitly. When building a test script (or any script for that matter), allowing silent failure could lead to bad surprises down the road.
I am working on a project on which i need to send data over USART to terminal.
I need to display the data as the numeric value (0-255) of the char (which collected from the EEPROM
i have managed to send the char as is to the terminal (using Putty or TerMite)
My problem starts where the value of the char is non-printable
That's why i will need to convert the value of the char to numeric
Example: when the data acquired from the EEPROM is 0x31 my routine will send '1' but i will need to send '049' or '49' to the terminal
void SendToSer(void) {
unsigned char Looper;
for (Looper=EEPROM_START;Looper<EEPROM_END;Looper++){
ReadEEPROM(Looper); //returns ReadResult
Write1USART((char) ReadResult); //Sends the ASCII
ClrWdt();
}
}
Thanks,
The sprintf as jolati suggested can be a good work horse in some situations or, even better, snprintf if it is available for your version of C18. Both routines follow the standard printf formatting (ex. https://en.wikipedia.org/wiki/Printf_format_string).
#include "stdio.h"
void main() {
char buffer[80];
unsigned char len, number = 152;
// Write at most 80 bytes to our buffer
len = snprintf(buffer, 80, "sprintf string, heres a number: %d", number);
// buffer now contains our string, len is the number of bytes written
// or
len = printf(buffer, "... %d",number);
}
Thanks , I've decided to take it the long way......
Here's what i've done is:
Manipulated the int value of the char to 3 new char
(i.e.) 243 became 3 chars - 50,52,51 (the ASCII of the digits)
(maybe its long and lame but it works like a charm)
heres the script....
void ConvertToNumeric(unsigned char IsValue, unsigned int LineNumber){
unsigned int SourceInt;
ClrWdt();
if (IsValue == 1){
SourceInt = (int) ReadResult;
}else{
SourceInt = (int) LineNumber;
LineNumber++;
}
ClrWdt();
switch (SourceInt/100){
case 2 : FirstChar = 50; SourceInt = SourceInt - 200; break;
case 1 : FirstChar = 49; SourceInt = SourceInt - 100; break;
case 0: FirstChar = 48; break;
}
switch (SourceInt/10){
case 9 :SecondChar = 57; SourceInt = SourceInt - 90; break;
case 8 :SecondChar = 56; SourceInt = SourceInt - 80; break;
case 7 :SecondChar = 55; SourceInt = SourceInt - 70; break;
case 6 :SecondChar = 54; SourceInt = SourceInt - 60; break;
case 5 :SecondChar = 53; SourceInt = SourceInt - 50; break;
case 4 :SecondChar = 52; SourceInt = SourceInt - 40; break;
case 3 :SecondChar = 51; SourceInt = SourceInt - 30; break;
case 2 :SecondChar = 50; SourceInt = SourceInt - 20; break;
case 1 :SecondChar = 49; SourceInt = SourceInt - 10; break;
case 0 :SecondChar = 48; break;
}
switch (SourceInt){
case 9: ThirdChar= 57; break;
case 8: ThirdChar= 56; break;
case 7: ThirdChar= 55; break;
case 6: ThirdChar= 54; break;
case 5: ThirdChar= 53; break;
case 4: ThirdChar= 52; break;
case 3: ThirdChar= 51; break;
case 2: ThirdChar= 50; break;
case 1: ThirdChar= 49; break;
case 0: ThirdChar= 48; break;
}
ResultInChars[0] = FirstChar;
ResultInChars[1] = SecondChar;
ResultInChars[2] = ThirdChar;
ResultInChars[3] = ' ';
ResultInChars[4] = NULL;
ResultInChars[5] = NULL;
ResultInChars[6] = NULL;
}
later i have used puts1USART with an array containing 3 above chars (FirstChar, SecondChar & ThirdChar)
i've also added a "lineNumber" before every 4 values and CrLf after the forth value
and it has resulted an output looks like that.....
output to terminal in Putty over Serial port
and its working......
thanks for your help
I would apriciate your suggestions,
Guy
I have zero experience with programming adruino but I have to test these robots for my job. I was told this code drives the robots foreword. When I run this code I get the error that 'set' is not declared in this scope. Help? Or let me know if this isn't even the right question to ask. Those libraries at the top are also with me, but I'm unsure if I need to post them to solve this particular problem.
#include <Lobotank.h>
#include <tank_Cwrap.h>
int temp_R=0;
int temp_L=0;
int c15=0;
void setup()
{
enableDebug();
//test sensors(1000);
set speed(125);
}
void loop()
{
update sensors();
int pattern = 0;
long rndm = random(0,10);
serial.println(rndm);
//serial.println(temp_L);
//serial.println(lf_left);
//serial.println(lf_mleft);
//serial.println(lf_mright);
//serial.println(lf_right);
if (lf_left>= 500)
pattern += 8;
if (lf_mleft >= 500)
pattern += 4;
if (lf_mright >= 500)
pattern += 2;
if (lf_right >= 500)
pattern += 1;
switch (pattern)
{
case 0:
if (temp_R ==1)
turnRight_hard();
else
turnAround_left()
break;
case 1:
turnRight_slight();
temp_R = 1;
break;
case 2:
turnRight_slight();
temp_R = 1;
break;
case 3:
delay(25);
turnRight_slight();
break;
case 6:
forward();
temp_R = 0;
c15 = 0;
break;
case 7: //turn right
turnRight_hard();
temp_R = 1;
break;
case 8:
turnleft_slight();
temp_R = 0;
break;
case 12:
delay(15);
turnLeft_slight();
break;
case 14: //turn left
turnLeft_hard();
break;
case 15:
delay(25);
if (rndm <= 5 && c15 <= 3)
turnleft_hard();
else
{
if (rndm >= 6 && c15 <= 3)
turnRight_hard();
else
{
if (c15 >= 5)
turnRight_hard();
else
{
if (c15>= 10)
stop();
}
}
}
c15++;
break;
}
This doesn't look like valid syntax:
set speed(125);
This looks like a function call, but functions can't have spaces in them. Maybe you meant one of these:
setspeed(125);
setSpeed(125);
set_speed(125);
Look in those .h files for a function similar to these, and make sure you call it with the correct name.
I have a written a small utility in D to convert the output of find -print0 to printf %b format. Such a utility already exists (nul2pfb from http://www.dwheeler.com/essays/filenames-in-shell.html), but the link is dead and I could not find the program, so I decided to implement it myself in D. I am using the following zsh command for testing:
diff <(find) <(for i in "$(find -print0 | dd | char2code)"; do printf '%b\n' "$i"; done)
The expected output is empty, but I find that some filenames that include a hyphen are handled wrong.
My source code is this:
import std.stdio;
import std.conv;
import std.ascii;
import std.c.stdlib;
void main()
{
foreach (ubyte[] mybuff; chunks(stdin, 4096)) {
encodeline (mybuff);
}
}
#safe void encodeline (ubyte[] mybuff) {
// char[] outstring;
foreach (ubyte i; mybuff) {
char b = to!char(i);
switch (i) {
case 'a': .. case 'z':
case 'A': .. case 'Z':
case '0': .. case '9':
case '/':
case '.':
case '_':
case ':': writeChar(b); break;
default: writeOctal(b); break;
case 0: writeChar ('\n'); break;
case '\\': writeString(`\\`); break;
case '\t': writeString(`\t`); break;
case '\n': writeString(`\n`); break;
case '\r': writeString(`\r`); break;
case '\f': writeString(`\f`); break;
case '\v': writeString(`\v`); break;
case '\a': writeString(`\a`); break;
case '\b': writeString(`\b`); break;
}
}
// writeString (outstring);
}
#trusted void writeString (string a)
{
write (a);
}
#trusted void writeOctal (int a)
{
try
{
writef ("\\%.#o", a); // leading 0 needed for for zsh printf '%b'
}
catch (std.format.FormatException b)
{
write ("Format exception in function writeOctal");
throw b;
}
}
#trusted void writeChar (char a)
{
try
{
write (a);
}
catch (std.format.FormatException b)
{
write ("Format exception in function writeChar");
throw b;
}
}
#trusted void writeNewline ()
{
writeln;
}
Here is a part of the diff output:
Correct filenames:
./.ibam/profile-004-battery
./.ibam/profile-034-charge
./.ibam/profile-054-charge
./.ibam/profile-045-battery
(a bunch of lines skipped)
---
Wrong filenames:
./.ibam/profileh04-battery
./.ibam/profileh34-charge
./.ibam/profileh54-charge
./.ibam/profileh45-battery
It seems like -0 is being replaced by h.
UPDATE: Replacing .# with .4 in the conversion specifier for writef fixed the problem but I still see differences in output of searches through /proc. However, this is also true when I do (as root)
diff <(find / print) <(find / print) > (myhomedirectory)/log.txt
so I have chosen to ignore it.
As it turned out, the problem was that whenever an octal escape sequence was followed by a number between 0 and 7 inclusive, and the original escape sequence was not already 4 octal digits long, the number became part of the octal escape sequence, causing printf %b to produce incorrect output. This was fixed by replacing the # by .4 in the conversion specifier in the D program.
This is the corrected source code, with some unneeded functions deleted:
import std.stdio;
import std.conv;
import std.ascii;
import std.c.stdlib;
void main()
{
foreach (ubyte[] mybuff; chunks(stdin, 4096)) {
encodeline (mybuff);
}
}
#safe void encodeline (ubyte[] mybuff) {
// char[] outstring;
foreach (ubyte i; mybuff) {
char b = to!char(i);
switch (i) {
case 'a': .. case 'z':
case 'A': .. case 'Z':
case '0': .. case '9':
case '/':
case '.':
case '_':
case ':': writeChar(b); break;
default: writeOctal(b); break;
case 0: writeChar ('\n'); break;
case '\\': writeString(`\\`); break;
case '\t': writeString(`\t`); break;
case '\n': writeString(`\n`); break;
case '\r': writeString(`\r`); break;
case '\f': writeString(`\f`); break;
case '\v': writeString(`\v`); break;
case '\a': writeString(`\a`); break;
case '\b': writeString(`\b`); break;
}
}
}
#trusted void writeString (string a)
{
write (a);
}
#trusted void writeOctal (int a)
{
writef ("\\%.4o", a); // leading 0 needed for for zsh printf '%b'
}
#trusted void writeChar (char a)
{
write (a);
}