1. 10

    This template:

    1. Doesn’t let the user specify a C compiler,
    2. Overrides CFLAGS from the system defaults/environment,
    3. Overrides LDFLAGS from the system defaults/environment.

    Project-specific CFLAGS and LDFLAGS should be set with += and the C compiler should be invoked with $(CC).

    Additionally, I find generating a .depend file much cleaner than littering .d files:

    depend: $(SRCS)
    	$(CC) $(CFLAGS) -MM $(SRCS) > .depend
    
    -include .depend
    
    1. 3

      Damn…I trounced the current high score (32704, I got 61768), but was expecting it to announce “game over” or something and exited the session without recording it. Oh well.

      1. 4

        Shit, sorry. I skipped implementing a game over check because it’s not entirely trivial.

        1. 1

          I did the same thing the first try, you could just leave a message at the bottom with instructions.

      1. 7

        Out of curiosity, is the web dead and we now write in groff?

        1. 9

          It’s mdoc, and one can dream.

          1. 3

            Why don’t you remove the top line with “FreeBSD Miscellaneous Information Manual”?

            1. 1

              Ah very well then, I forgive you.

            2. 5

              Just this guy.

            1. 1

              So when might I want a config-less editor? Genuine question.

              1. 3

                The article spends two paragraphs on this…

                1. 6

                  The thing is that the article is predicated on the assumption that the editor you use has to be on the system where you’re editing the file. If there are constraints preventing you from setting the system up as you want then you just have to use what’s on the system. If that’s vi, then you use vi. If it’s another editor then you use that. End of story.

                  But if there are no constraints preventing you from running an sshd on the system, then you can use the emacs on your laptop, with your entire config, to access its file system using tramp and you don’t have to feel like you’re editing with one hand tied behind your back.

                  Maybe I should have phrased my question, given the choice, when would I want to choose to use a config-less editor?

                  1. 3

                    Hello bon, here are my answers to your questions, I hope they are helpful.

                    If there are constraints preventing you from setting the system up as you want then you just have to use what’s on the system. If that’s vi, then you use vi. If it’s another editor then you use that. End of story.

                    Constraints are certainly one reason why I use vi on remote systems (I don’t always have sudo access :)), but sometimes I also just don’t want to take the time and put in the effort of installing my personal configuration of Emacs. Knowing how to use vi certainly releases some of the “pressure” of transferring my config directory: I just go “meh”, use vi, and I’m happy.

                    But if there are no constraints preventing you from running an sshd on the system, then you can use the emacs on your laptop, with your entire config, to access its file system using tramp and you don’t have to feel like you’re editing with one hand tied behind your back.

                    I don’t like Tramp in Emacs for two reasons. The main reason is that Tramp assumes that I know which file I want to edit, but very often when I’m on a remote system, it’s because it’s a server that’s misbehaving and I’m looking around for the issue. I want to be shelled into the machine and use all the Unix tools that I’m used to to find the problem: find, grep, htop, lsof, etc. I don’t know yet which file I want to edit, I’m still just fishing around for it.

                    Once I find some candidates, I want to inspect them, determine if they’re what I’m looking for, and perhaps edit them. If I’m using the editor on the remote machine, that’s done really quickly. With Tramp, I need to switch from the ssh terminal to my Emacs window and try and remember the syntax for opening a remote file—that’s my other reason for not liking Tramp, I always forget its syntax—before I know if that file was interesting or not. That cuts into my flow, and so I don’t like to use Tramp.

                    1. 2

                      With Tramp, I need to switch from the ssh terminal to my Emacs window and try and remember the syntax for opening a remote file—that’s my other reason for not liking Tramp, I always forget its syntax—before I know if that file was interesting or not. That cuts into my flow, and so I don’t like to use Tramp.

                      What do you mean with “syntax”? It’s just a regular C-x C-f and then /ssh:[ssh alias]/ [RET] and Tramp is turned on. Ivy even let’s me just type /ssh: and choose a host. You can even use eshell, and just type cd /[host]: and it’s the same as above. My issue is rather that it’s often too slow for a quick edit (as you mention), since Tramp has a bit of an overhead, due to all the data being transfered in base 62.

                      1. 2

                        If the remote system is running sshd, you can also use sshfs to mount the remote filesystem on your development machine. Probably not worth it to edit a single file, but it does make it easy to use any editor you like, along with any other tools you have on your development machine which aren’t on the target (Can do some exploration to find the file to edit, but that will depend whether exploration consists of looking inside various files and directories or also involves running executables on the remote machine). It’s also handy for things like using a visual diff tool to compare a remote file or directory with a local file or directory.

                        1. 2

                          The main reason is that Tramp assumes that I know which file I want to edit, but very often when I’m on a remote system, it’s because it’s a server that’s misbehaving and I’m looking around for the issue. I want to be shelled into the machine and use all the Unix tools that I’m used to to find the problem: find, grep, htop, lsof, etc. I don’t know yet which file I want to edit, I’m still just fishing around for it.

                          As @zge mentions (and I think is important enough to reïterate), this is actually possible with Tramp: you can shell out with M-!, and run eshell, and everything just works as you would want. There’s no need for an ssh session in a terminal emulator at all, because emacs can handle it.

                          As a practical matter (again, as @zge mentions), the performance is not necessarily as great as it could be. Still, it’s pretty powerful & it’s very often useful to me.

                  1. 4

                    The idea is good but… It’s almost like the whole point of spreadsheets are to have a powerful way of manipulating data that doesn’t require much programming skills but still can do a whole lot of value adding.

                    Of course you can do all the summations using a range of command line tools… But does it really but pressing ALT and =?

                    I remain a bit doubtful for the approach :)

                    1. 3

                      For doing calculations my approach is to import the CSV/TSV into SQLite and query it there. It’s remarkably faster than importing into a spreadsheet program and doesn’t have arbitrary row count limitations.

                      1. 3

                        I didn’t know that was possible… Seems like a nice feature to know about. For future reference 1 is a link to the documentation about importing and exporting CSV files. For TSV files, see 2

                        1. 2

                          Years and years ago, I was cooking up a Django project that would read in downloadable CSV bank statements from my online bank.

                          The purpose was this, but as the statement downloads can’t be automated and banks have been improving their reporting features, the project dwindled off.

                          Being able to query by SQL or Django admin is a superpower, though.

                          This Vim TSV business might be better suited for eg. how translators sometimes use CSV/TSV as an interchange format.

                      1. 3

                        I use neovim’s :Man command and K binding a lot, along with ctags integration.

                        1. 12

                          I don’t like tools that make using awk or cut harder.

                          The output could be improved without using the parenthesis around the bytes, or having a flag .

                          1. 5

                            Tools should have optional JSON output so I can use jq queries instead of awk or cut :P

                            1. 4

                              I really like jq too :)

                              1. 2

                                https://github.com/Juniper/libxo

                                This is integrated in most FreeBSD utilities.

                                1. 3

                                  We should all switch to Powershell, where values have types and structure, instead of switching to a different text format.

                              1. 1

                                No mention of the standard assert.h? Don’t implement your own version of a standard function just because.

                                1. 1

                                  For the leading-break, this is just a way to put a break for the previous case. In fact, my auto-formatter just moves it to the normal place for the previous case. It’s another way to remember to always break your cases I guess.

                                  1. 1

                                    Yes, but it formats nicer for single-line cases and it is much easier to spot a missing break.

                                    1. 1

                                      What I’m saying is (for my formatter at least) is it won’t do that as a single line.

                                      But I get it, it shifts your thinking from “I should break this case to prevent fall through to next” and shifts to “I’ll put a break before to prevent fall through from previous.”

                                  1. 3

                                    One that people keep forgetting in initialisers is compound literals.

                                    void foo(struct bar*){ … }

                                    foo(&(struct bar){.baz = 0xdeadbeef});

                                    1. 1

                                      Can you really use & there? iirc C won’t let you pass &0xDEADBEEF, for example.

                                      1. 2

                                        Can you really use & there?

                                        Try it out and see…if your compiler implements C99 it should work.

                                        iirc C won’t let you pass &0xDEADBEEF, for example.

                                        Not with that exact syntax, but you can do e.g. int* foo = (int[]){ 12, };.

                                    1. 6

                                      First example under-utilizes “nice” initializer syntax, in my opinion – could be written as

                                      struct {
                                              struct pollfd fds[2];
                                      } loop = {
                                             .fds = {
                                                { .fd = STDIN_FILENO, .events = POLLIN, },
                                                { .fd = STDOUT_FILENO, .events = POLLOUT, },
                                              },
                                      };
                                      

                                      A related designated-initializer syntax for arrays is particularly useful for arrays indexed by enums:

                                      void handle_foo(void);
                                      void handle_bar(void);
                                      enum { Foo, Bar, };
                                      void (*handlers[])(void) = {
                                        [Foo] = handle_foo,
                                        [Bar] = handle_bar,
                                      };
                                      
                                      1. 4

                                        Yeah the example is a bit contrived to demonstrate that designators can be chained together rather than having to nest more braces.

                                      1. 17

                                        Perhaps nitpicky, but I wouldn’t suggest recommending VLAs in a document like this. The consensus seems to be that it’s probably never wise to use them. They were also made optional in C11 (meaning compilers no longer have to support them and you have to test for __STDC_NO_VLA__ to check support). It’s basically syntactic sugar for the same thing alloca() does, which has all the same problems as VLAs:

                                        The basic argument against them goes something like this: if the variable size argument(s) for your VLAs could end up being very large at runtime, they could overflow stack space and cause a crash. If your answer to this proposed crash (for a given VLA usage) is that your VLA size arguments are already constrained to stack-reasonable sizes, then it would be more efficient, compatible, and simple to simply declare a fixed-length stack array of the maximum possible size (since stack allocations just adjust a stack frame pointer). If you really do need the possibility of very large sizes and don’t want to possibly crash, the only sane approach is going to be to use heap allocatiors like malloc() and friends.

                                        1. 7

                                          I agree with you, and I don’t find this nitpicky at all. Use of VLAs is lately discouraged in the kernel, and there’s an active effort to remove them[1]. They’re not secure, and have slower performance, so a document about pleasant C should in my opinion discourage them, or not mention them at all, but not do the opposite.

                                          1. 8

                                            I don’t really mean to be encouraging use of specific C features here, just pointing out some things that I find pleasant to write. Perhaps a CAVEATS section is needed.

                                            1. 3

                                              Probably a good idea.

                                              1. 2

                                                Fair enough, sorry for hijacking your otherwise very nice page:)

                                            2. 4

                                              Neither malloc nor alloca are capable of the behaviour I pointed out that I found useful, unfortunately.

                                              1. 2

                                                How about:

                                                T (*dyn)[len][h][w] = malloc(len * h * w * sizeof(T));
                                                fread(dyn, h * w, len, stdin);
                                                

                                                one difference is that you now have to write (*dyn)[i][j][k] instead of arr[i][j][k]. Is there any issue that I’m not familiar with that can be caused by this approach?

                                                1. 2

                                                  I thought multiplying values inside of malloc sizing was bad form due to overflow risks?

                                                  1. 1

                                                    It would have to be done here one way or another, since calloc only does 1D arrays, sure you can do:

                                                    size_t dyn_len = len * h * w * sizeof(T)
                                                    T (*dyn)[len][h][w] = malloc(dyn_len);
                                                    ...
                                                    

                                                    or have a function that does it:

                                                    void *new_3d_array(size_t len, size_t h, size_t w, size_t type_size) {
                                                        return malloc(len * h * w * type_size);
                                                    }
                                                    T (*dyn)[len][h][w] = new_3d_array(len, h, w, sizeof(T));
                                                    

                                                    or….

                                                    #define SIZEOF_3D_ARRAY(X, Y, Z, TYPE) ((X) * (Y) * (Z) * sizeof((TYPE)))
                                                    T (*dyn)[len][h][w] = malloc(SIZEOF_3D_ARRAY(len, h, w, T));
                                                    

                                                    If you often have to work with 3D arrays then you should definitely put an extra layer there that multiplies for you, but I didn’t do that here, because the example in the page was about convenience, and I wanted to show mallocing that can be used in exactly the same way with fread.

                                                    Edit:

                                                    Here’s a non performant version but with the overflow handling:

                                                    void * new_3d_array(size_t len, size_t h, size_t w, size_t sizeof_type) {
                                                            size_t hw = h * w;
                                                            if (h != 0 &&  hw / h != w)
                                                                    return NULL;
                                                    
                                                            size_t hwlen = hw * len;
                                                            if (hw != 0 && hwlen / hw != len)
                                                                    return NULL;
                                                    
                                                            size_t sothwlen = hwlen * sizeof_type;
                                                            if (hwlen != 0 && sothwlen / hwlen != sizeof_type)
                                                                    return NULL;
                                                    
                                                            return malloc(sothwlen);
                                                    }
                                                    
                                                    func(size_t len, size_t h, size_t w) {
                                                            T (*dyn)[len][h][w] = new_3d_array(len, h, w, sizeof(T));
                                                            assert(dyn != NULL);
                                                            fread(dyn, h * w, len, stdin);  // Nothing stops h * w from overflowing..
                                                    }
                                                    
                                              2. 3

                                                VLAs could be more fair if there would be a way to map them to a custom heap allocator, there’s nothing in the spec itself that dictates the allocation to be intertwined with your stack frame and obvious reasons why you would want to avoid just that. The whole principle is to get access to dynamic allocation tied to the scope of ‘auto’, what pool it is taken from is secondary - but with sizeof() being possibly dynamic, get something that isn’t malloc heap or compiler managed stack.

                                              1. 1

                                                Is there a better tag to use for documentation and/or markup languages?

                                                1. 2

                                                  Does anyone know a BDF to PSF (for the Linux console) converter? Both names are so close to PDF it’s impossible to Google. If not, I’m probably about to write my own.

                                                  1. 2

                                                    The font editor I use to create Spleen, gbdfed, has an option to export PSF files.

                                                    1. 1

                                                      Because I’m dense… The layout displayed in gbdfed gets translated to my local codepage via psfu / the actual glyph names, right?

                                                      Also, in case people want to try with gbdfed themselves, you need to populate the first 32 codepoints or will get a weird error when trying to load the font and the screen will look bizarre. It seems to shift the codepoints down by 32 if you leave those blank…

                                                      1. 1

                                                        Yeah I just tried exporting all the BDFs to PSF and none of them work properly. Either they error out setfont or they fill the screen with garbage.

                                                    2. 2

                                                      archlinux has one in aur via the debian thingy usage should be a simple manpage away…

                                                    1. 4

                                                      That textfile blog style is absolutely beautiful. @causal_agent, thanks for putting in the notice on how you created it!

                                                      1. 1

                                                        Apart from the repo (https://code.causal.agency/june/text.causal.agency), where can I find more info on the creation by the author? Love it.

                                                        1. 2

                                                          Hi! What would you like to know?

                                                          1. 2

                                                            I am not yet a *nix nor BSD + manpage pro, but I love the idea of tech posts as man pages / .txt files. Are the .7 source files used for a specific reason? The script for building is so simple, as well.

                                                            I’m really keen on simplicity these days, especially when it comes to the bloat of the web, so I try to set a good example, and this is something I can learn from for sure.

                                                            1. 4

                                                              I’m really keen on simplicity these days, especially when it comes to the bloat of the web, so I try to set a good example, and this is something I can learn from for sure.

                                                              I’d be the first person to say, “Yeah, make things simpler!” but a plaintext page using spaces for indentation is actually a degraded experience online. The sweet spot for the web is probably a tasteful use of HTML with no Javascript, and a pinch of CSS.

                                                              Look, even the OpenBSD man pages are rendered online with HTML rather than text. https://man.openbsd.org/mdoc.7 Try resizing the page width and watch how it adjusts to stay readable. Now try different widths with text.casual.agency and look how you get jagged line wrap.

                                                              Perhaps you’ll argue, “Resize the width, what you do you mean? I’m on lynx!” But even lynx takes cues from HTML tags to render the page better.

                                                              Finally, you can probably have mdoc output to HTML rather than text and not have to change your page description. Mandoc has a “-Thtml” flag for this, and maybe mdoc has something similar.

                                                              1. 1

                                                                Fair points, and that’s exactly what I was hoping I’d find (when it comes to HTML). Being able to build for .txt and .html files is something I’d like to explore, and you’ve helped. And thanks for the -Thtml lead.

                                                              2. 2

                                                                The extension used for man pages is the digit corresponding to the manual section they’re for. 7 is the “Miscellaneous Information” section which is the only one that fits. You can read about mandoc and mdoc at http://mandoc.bsd.lv, in particular the mdoc(7) page for authors http://mandoc.bsd.lv/man/mdoc.7.html. I might write a little about what I like about mdoc soon.

                                                                There’s some interesting background on the build command, mandoc | sed $'s/.\b//g'. When man pages are formatted for display as text, bold text is output as “A\bA” (where “\b” is ASCII backspace) and underlined text is output as “_\bA”, because that was how you achieved those on a teletypewriter. Print A, move back, print A again over it, print underscore, move back, print A over it. Nowadays it’s actually the pager less(1) which interprets those sequences and renders them in your terminal’s bold and underline modes. If you just print the output of mandoc to the terminal, it will look like plain text with no formatting, because the terminal interprets the backspaces and just deletes the first “A” or “_”. The sed command removes those sequences to create a plain text file.

                                                                1. 1

                                                                  Thank you for the detailed response; I had no idea about that background nor why the extension was .7. So interesting! I’ll read up on mandoc & mdoc, and I look forward to your writeup.

                                                                  Thanks again

                                                        1. 1

                                                          Nice! I’ll have to make an Emacs template for when I first open a Makefile to insert that boilerplate. I’d also add the code to generate the header file dependency tree using the correct g++ flags.

                                                          1. 5

                                                            Here’s the rule I use (GNUMake) to do the dependencies:

                                                            depend:
                                                            	makedepend -Y -- $(CFLAGS) -- $(shell find . -name '*.c') 2>/dev/null
                                                            

                                                            This will exclude the system header files, but include all local headerfiles. Remove the -Y to include system headers.

                                                            1. 2

                                                              On BSD:

                                                              depend:
                                                              	mkdep $(CFLAGS) $(SRCS)
                                                              
                                                              1. 1

                                                                Better than this crufty make command I’ve been carrying around for probably 20 years!

                                                                MAKEDEPS=@echo Making $*.d; \ 
                                                                    set -e; rm -f $@; \ 
                                                                    $(CXX) -MM $(CXXFLAGS) $< > $@.$$$$; \ 
                                                                    sed 's,\(.*$(*F)\)\.o[ :]*,$(*D)/\1.o $@ : ,g' < $@.$$$$ > $@; \ 
                                                                    rm -f $@.$$$$ 
                                                                
                                                                %.d: %.cpp 
                                                                    $(MAKEDEPS)
                                                                
                                                                1. 2

                                                                  Make already gets such overwhelmingly negative press so let’s not leave this as-is lest others think this is how things have to be. Here is mine:

                                                                  %.d: %.cpp
                                                                      $(CXX) -MM -MT "$(basename $@).d $(basename $@).o" $< > $@
                                                                  
                                                                  1. 1

                                                                    Nice! I’m not even sure where I got mine, just a case of “leave it alone it works”.

                                                            1. 1

                                                              Note that declaring multiple files on the left side of the colon might cause the rule to be run several times when using parallel make. You should declare just one and then declare the others as dependent on the first, like this:

                                                              foo.o: foo.h
                                                              bar.o baz.o qux.o: foo.o
                                                              

                                                              Or consider only using a single witness file instead.

                                                              1. 1

                                                                I’m not sure I get this. bar.o doesn’t depend on foo.o. Wouldn’t this needlessly serialize building foo.o before the others?

                                                                1. 1

                                                                  Sorry, got confused. I wanted to say that make doesn’t deal that well with commands that output more than one file, which is where my hack is useful.

                                                                  1. 1

                                                                    The intention with listing several files left of the colon isn’t to have one command produce several files, but to have the same command produce each file. In the header file dependency case, the .c.o suffix rule is still used to create each .o file.

                                                              1. 6

                                                                You don’t need to specify the compile line if it’s a C or C++ file:

                                                                foo : $(OBJS)
                                                                

                                                                is enough. Here’s the Makefile (GNUMake, excluding dependencies) for a 150,000+ line project I have:

                                                                %.a :
                                                                	$(AR) $(ARFLAGS) $@ $?
                                                                
                                                                all: viola/viola
                                                                
                                                                libIMG/libIMG.a     : $(patsubst %.c,%.o,$(wildcard libIMG/*.c))
                                                                libXPA/src/libxpa.a : $(patsubst %.c,%.o,$(wildcard libXPA/src/*.c))
                                                                libStyle/libStyle.a : $(patsubst %.c,%.o,$(wildcard libStyle/*.c))
                                                                libWWW/libWWW.a     : $(patsubst %.c,%.o,$(wildcard libWWW/*.c))
                                                                viola/viola         : $(patsubst %.c,%.o,$(wildcard viola/*.c))	\
                                                                		libIMG/libIMG.a		\
                                                                		libXPA/src/libxpa.a	\
                                                                		libStyle/libStyle.a	\
                                                                		libWWW/libWWW.a
                                                                

                                                                I have a rule to automatically make the dependencies.

                                                                1. 3

                                                                  foo: $(OBJS) with no command is not enough for non-GNU make.

                                                                  1. 9

                                                                    Ah. I haven’t used a non-GNUMake in … 20 years?

                                                                    1. 2

                                                                      indeed ! it is way better to use a portable make, rather than write portable makefiles :)

                                                                      1. 3

                                                                        In that case I’ll use NetBSD make ;)

                                                                  2. 1

                                                                    for < 10k line projects i tend to just do ‘cc *.c’ :P usually it is fast enough

                                                                    1. 1

                                                                      Meanwhile, I have a 2.5kloc project where a full recompile takes 30 seconds, so incremental compilation is kind of necessary :p C++ is slooow.

                                                                    2. 1

                                                                      Is this a revived ViolaWWW?

                                                                      1. 1

                                                                        Somewhat. It’s one of those “I want to do something but I don’t know what” type projects where I clean up the code to get a clean compile (no warnings—I still have a ways to go). It works on a 32-bit system, but crashes horribly on 64-bit systems because of the systemic belief that sizeof(int)==sizeof(long)==sizeof(void *).

                                                                      1. 1

                                                                        Forgot to read your write-up when you posted it originally. Thanks for the reminder, it’s great stuff.

                                                                      1. 1

                                                                        Sounds like a lot more cding than I do. I tend to cd only once per shell session to a project directory and then run my editor, build tool, git and whatever else from there. I’m sure I spend a lot more time typing make and git than cd.